15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2008 Apple Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1.  Redistributions of source code must retain the above copyright
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     notice, this list of conditions and the following disclaimer.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2.  Redistributions in binary form must reproduce the above copyright
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     notice, this list of conditions and the following disclaimer in the
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     documentation and/or other materials provided with the distribution.
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     its contributors may be used to endorse or promote products derived
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     from this software without specific prior written permission.
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
30bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)#include "core/accessibility/AXTable.h"
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/accessibility/AXObjectCache.h"
33bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)#include "core/accessibility/AXTableCell.h"
34bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)#include "core/accessibility/AXTableColumn.h"
35bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)#include "core/accessibility/AXTableRow.h"
36d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#include "core/dom/ElementTraversal.h"
37d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#include "core/html/HTMLCollection.h"
3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLTableCaptionElement.h"
3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLTableCellElement.h"
40d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include "core/html/HTMLTableColElement.h"
4153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLTableElement.h"
42d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#include "core/html/HTMLTableRowElement.h"
4376c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)#include "core/html/HTMLTableRowsCollection.h"
44d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#include "core/html/HTMLTableSectionElement.h"
4553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderTableCell.h"
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
47c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using namespace HTMLNames;
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
51bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)AXTable::AXTable(RenderObject* renderer)
52bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    : AXRenderObject(renderer)
53d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    , m_headerContainer(nullptr)
54bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    , m_isAXTable(true)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
58bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)AXTable::~AXTable()
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
62bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)void AXTable::init()
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
64bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    AXRenderObject::init();
65bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    m_isAXTable = isTableExposableThroughAccessibility();
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
68bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)PassRefPtr<AXTable> AXTable::create(RenderObject* renderer)
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
70bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    return adoptRef(new AXTable(renderer));
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
73bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)bool AXTable::hasARIARole() const
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!m_renderer)
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
7702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    AccessibilityRole ariaRole = ariaRoleAttribute();
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (ariaRole != UnknownRole)
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return false;
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
85bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)bool AXTable::isAXTable() const
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!m_renderer)
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
8902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
90bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    return m_isAXTable;
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
93d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)static bool elementHasAriaRole(const Element* element)
94d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles){
95d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (!element)
96d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        return false;
97d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
98d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    const AtomicString& ariaRole = element->fastGetAttribute(roleAttr);
99d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    return (!ariaRole.isNull() && !ariaRole.isEmpty());
100d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)}
101d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
102bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)bool AXTable::isDataTable() const
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
104d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (!m_renderer || !node())
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Do not consider it a data table is it has an ARIA role.
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (hasARIARole())
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // When a section of the document is contentEditable, all tables should be
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // treated as data tables, otherwise users may not be able to work with rich
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // text editors that allow creating and editing tables.
114197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    if (node() && node()->hasEditableStyle())
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // This employs a heuristic to determine if this table should appear.
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Only "data" tables should be exposed as tables.
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Unfortunately, there is no good way to determine the difference
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // between a "layout" table and a "data" table.
121e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderTable* table = toRenderTable(m_renderer);
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Node* tableNode = table->node();
124d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (!isHTMLTableElement(tableNode))
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
127d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // Do not consider it a data table if any of its descendants have an ARIA role.
128e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    HTMLTableElement* tableElement = toHTMLTableElement(tableNode);
129d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (elementHasAriaRole(tableElement->tHead()))
130d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        return false;
131d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (elementHasAriaRole(tableElement->tFoot()))
132d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        return false;
133d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
134d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    RefPtrWillBeRawPtr<HTMLCollection> bodies = tableElement->tBodies();
135d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    for (unsigned bodyIndex = 0; bodyIndex < bodies->length(); ++bodyIndex) {
136d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        Element* bodyElement = bodies->item(bodyIndex);
137d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        if (elementHasAriaRole(bodyElement))
138d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)            return false;
139d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    }
140d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
14176c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    RefPtrWillBeRawPtr<HTMLTableRowsCollection> rows = tableElement->rows();
14276c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    unsigned rowCount = rows->length();
14376c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    for (unsigned rowIndex = 0; rowIndex < rowCount; ++rowIndex) {
144c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        HTMLTableRowElement* rowElement = rows->item(rowIndex);
145d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        if (elementHasAriaRole(rowElement))
146d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)            return false;
147c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        RefPtrWillBeRawPtr<HTMLCollection> cells = rowElement->cells();
148c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        for (unsigned cellIndex = 0; cellIndex < cells->length(); ++cellIndex) {
149c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)            if (elementHasAriaRole(cells->item(cellIndex)))
150c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                return false;
151d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        }
152d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    }
153d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
154d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // If there is a caption element, summary, THEAD, or TFOOT section, it's most certainly a data table
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!tableElement->summary().isEmpty() || tableElement->tHead() || tableElement->tFoot() || tableElement->caption())
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
157e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // if someone used "rules" attribute than the table should appear
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!tableElement->rules().isEmpty())
16002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        return true;
161926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
162926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // if there's a colgroup or col element, it's probably a data table.
163d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (Traversal<HTMLTableColElement>::firstChild(*tableElement))
164d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        return true;
16502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // go through the cell's and check for tell-tale signs of "data" table status
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // cells have borders, or use attributes like headers, abbr, scope or axis
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    table->recalcSectionsIfNeeded();
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderTableSection* firstBody = table->firstBody();
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!firstBody)
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
17202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int numCols = firstBody->numColumns();
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int numRows = firstBody->numRows();
17502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
176926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // If there's only one cell, it's not a good AXTable candidate.
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (numRows == 1 && numCols == 1)
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
179926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
180926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // If there are at least 20 rows, we'll call it a data table.
181926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (numRows >= 20)
182926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return true;
18302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
184926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // Store the background color of the table to check against cell's background colors.
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderStyle* tableStyle = table->style();
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!tableStyle)
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1888abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    Color tableBGColor = tableStyle->visitedDependentColor(CSSPropertyBackgroundColor);
18902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // check enough of the cells to find if the table matches our criteria
19102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    // Criteria:
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //   1) must have at least one valid cell (and)
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //   2) at least half of cells have borders (or)
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //   3) at least half of cells have different bg colors than the table, and there is cell spacing
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned validCellCount = 0;
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned borderedCellCount = 0;
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned backgroundDifferenceCellCount = 0;
198926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    unsigned cellsWithTopBorder = 0;
199926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    unsigned cellsWithBottomBorder = 0;
200926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    unsigned cellsWithLeftBorder = 0;
201926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    unsigned cellsWithRightBorder = 0;
20202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2038abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    Color alternatingRowColors[5];
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int alternatingRowColorCount = 0;
20502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int headersInFirstColumnCount = 0;
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int row = 0; row < numRows; ++row) {
20802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int headersInFirstRowCount = 0;
21002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        for (int col = 0; col < numCols; ++col) {
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            RenderTableCell* cell = firstBody->primaryCellAt(row, col);
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!cell)
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            Node* cellNode = cell->node();
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!cellNode)
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
21702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (cell->width() < 1 || cell->height() < 1)
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
22002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            validCellCount++;
22202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
223bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            bool isTHCell = cellNode->hasTagName(thTag);
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // If the first row is comprised of all <th> tags, assume it is a data table.
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!row && isTHCell)
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                headersInFirstRowCount++;
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // If the first column is comprised of all <th> tags, assume it is a data table.
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!col && isTHCell)
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                headersInFirstColumnCount++;
23102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // in this case, the developer explicitly assigned a "data" table attribute
233d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            if (isHTMLTableCellElement(*cellNode)) {
234d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                HTMLTableCellElement& cellElement = toHTMLTableCellElement(*cellNode);
235d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                if (!cellElement.headers().isEmpty() || !cellElement.abbr().isEmpty()
236d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                    || !cellElement.axis().isEmpty() || !cellElement.scope().isEmpty())
237bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)                    return true;
238bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            }
23902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            RenderStyle* renderStyle = cell->style();
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!renderStyle)
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
244926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            // If the empty-cells style is set, we'll call it a data table.
245926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (renderStyle->emptyCells() == HIDE)
246926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                return true;
247926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
248926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            // If a cell has matching bordered sides, call it a (fully) bordered cell.
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if ((cell->borderTop() > 0 && cell->borderBottom() > 0)
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                || (cell->borderLeft() > 0 && cell->borderRight() > 0))
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                borderedCellCount++;
252926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
253926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            // Also keep track of each individual border, so we can catch tables where most
254926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            // cells have a bottom border, for example.
255926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (cell->borderTop() > 0)
256926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                cellsWithTopBorder++;
257926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (cell->borderBottom() > 0)
258926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                cellsWithBottomBorder++;
259926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (cell->borderLeft() > 0)
260926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                cellsWithLeftBorder++;
261926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (cell->borderRight() > 0)
262926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                cellsWithRightBorder++;
26302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
264926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            // If the cell has a different color from the table and there is cell spacing,
265926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            // then it is probably a data table cell (spacing and colors take the place of borders).
2668abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)            Color cellColor = renderStyle->visitedDependentColor(CSSPropertyBackgroundColor);
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (table->hBorderSpacing() > 0 && table->vBorderSpacing() > 0
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                && tableBGColor != cellColor && cellColor.alpha() != 1)
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                backgroundDifferenceCellCount++;
27002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
271926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            // If we've found 10 "good" cells, we don't need to keep searching.
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (borderedCellCount >= 10 || backgroundDifferenceCellCount >= 10)
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return true;
27402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // For the first 5 rows, cache the background color so we can check if this table has zebra-striped rows.
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (row < 5 && row == alternatingRowColorCount) {
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                RenderObject* renderRow = cell->parent();
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (!renderRow || !renderRow->isBoxModelObject() || !toRenderBoxModelObject(renderRow)->isTableRow())
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    continue;
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                RenderStyle* rowRenderStyle = renderRow->style();
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (!rowRenderStyle)
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    continue;
2838abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)                Color rowColor = rowRenderStyle->visitedDependentColor(CSSPropertyBackgroundColor);
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                alternatingRowColors[alternatingRowColorCount] = rowColor;
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                alternatingRowColorCount++;
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
28802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!row && headersInFirstRowCount == numCols && numCols > 1)
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return true;
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (headersInFirstColumnCount == numRows && numRows > 1)
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
29502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // if there is less than two valid cells, it's not a data table
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (validCellCount <= 1)
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
29902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // half of the cells had borders, it's a data table
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned neededCellCount = validCellCount / 2;
302926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (borderedCellCount >= neededCellCount
303926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        || cellsWithTopBorder >= neededCellCount
304926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        || cellsWithBottomBorder >= neededCellCount
305926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        || cellsWithLeftBorder >= neededCellCount
306926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        || cellsWithRightBorder >= neededCellCount)
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
30802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // half had different background colors, it's a data table
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (backgroundDifferenceCellCount >= neededCellCount)
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Check if there is an alternating row background color indicating a zebra striped style pattern.
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (alternatingRowColorCount > 2) {
3158abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)        Color firstColor = alternatingRowColors[0];
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (int k = 1; k < alternatingRowColorCount; k++) {
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // If an odd row was the same color as the first row, its not alternating.
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (k % 2 == 1 && alternatingRowColors[k] == firstColor)
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return false;
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // If an even row is not the same as the first row, its not alternating.
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!(k % 2) && alternatingRowColors[k] != firstColor)
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return false;
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
32602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return false;
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
32902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
330bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)bool AXTable::isTableExposableThroughAccessibility() const
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // The following is a heuristic used to determine if a
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // <table> should be exposed as an AXTable. The goal
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // is to only show "data" tables.
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!m_renderer)
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If the developer assigned an aria role to this, then we
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // shouldn't expose it as a table, unless, of course, the aria
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // role is a table.
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (hasARIARole())
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return isDataTable();
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
348bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)void AXTable::clearChildren()
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
350bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    AXRenderObject::clearChildren();
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_rows.clear();
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_columns.clear();
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_headerContainer) {
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_headerContainer->detachFromParent();
356d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        m_headerContainer = nullptr;
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
360bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)void AXTable::addChildren()
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
362bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    if (!isAXTable()) {
363bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        AXRenderObject::addChildren();
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
36602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
36702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    ASSERT(!m_haveChildren);
36802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_haveChildren = true;
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!m_renderer || !m_renderer->isTable())
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
37202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderTable* table = toRenderTable(m_renderer);
3748abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    AXObjectCache* axCache = m_renderer->document().axObjectCache();
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
376926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // Go through all the available sections to pull out the rows and add them as children.
377926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    table->recalcSectionsIfNeeded();
378926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    RenderTableSection* tableSection = table->topSection();
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!tableSection)
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
38102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderTableSection* initialTableSection = tableSection;
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    while (tableSection) {
38402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
385bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        HashSet<AXObject*> appendedRows;
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        unsigned numRows = tableSection->numRows();
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (unsigned rowIndex = 0; rowIndex < numRows; ++rowIndex) {
38802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
389926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            RenderTableRow* renderRow = tableSection->rowRendererAt(rowIndex);
390926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (!renderRow)
391926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                continue;
39202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
393bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            AXObject* rowObject = axCache->getOrCreate(renderRow);
394926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (!rowObject->isTableRow())
395926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                continue;
39602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
397bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            AXTableRow* row = toAXTableRow(rowObject);
398926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            // We need to check every cell for a new row, because cell spans
399926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            // can cause us to miss rows if we just check the first column.
400926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (appendedRows.contains(row))
401926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                continue;
40202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
403926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            row->setRowIndex(static_cast<int>(m_rows.size()));
404926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            m_rows.append(row);
405926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (!row->accessibilityIsIgnored())
406926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                m_children.append(row);
407926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            appendedRows.add(row);
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
40902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        tableSection = table->sectionBelow(tableSection, SkipEmptySections);
4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
41202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // make the columns based on the number of columns in the first body
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned length = initialTableSection->numColumns();
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = 0; i < length; ++i) {
416bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        AXTableColumn* column = toAXTableColumn(axCache->getOrCreate(ColumnRole));
4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        column->setColumnIndex((int)i);
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        column->setParent(this);
4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_columns.append(column);
4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!column->accessibilityIsIgnored())
4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            m_children.append(column);
4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
42302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
424bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    AXObject* headerContainerObject = headerContainer();
4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (headerContainerObject && !headerContainerObject->accessibilityIsIgnored())
4265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_children.append(headerContainerObject);
4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
42802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
429bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)AXObject* AXTable::headerContainer()
4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_headerContainer)
4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return m_headerContainer.get();
43302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
434bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    AXMockObject* tableHeader = toAXMockObject(axObjectCache()->getOrCreate(TableHeaderContainerRole));
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tableHeader->setParent(this);
4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_headerContainer = tableHeader;
4385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_headerContainer.get();
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
441bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)AXObject::AccessibilityChildrenVector& AXTable::columns()
4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    updateChildrenIfNecessary();
44402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_columns;
4465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
448bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)AXObject::AccessibilityChildrenVector& AXTable::rows()
4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    updateChildrenIfNecessary();
45102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_rows;
4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
45402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
455bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)void AXTable::columnHeaders(AccessibilityChildrenVector& headers)
4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!m_renderer)
4585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
45902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    updateChildrenIfNecessary();
46102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned colCount = m_columns.size();
4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned k = 0; k < colCount; ++k) {
464bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        AXObject* header = toAXTableColumn(m_columns[k].get())->headerObject();
4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!header)
4665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
4675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        headers.append(header);
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
47002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
471bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)void AXTable::cells(AXObject::AccessibilityChildrenVector& cells)
4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!m_renderer)
4745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
47502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    updateChildrenIfNecessary();
47702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int numRows = m_rows.size();
4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int row = 0; row < numRows; ++row) {
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        AccessibilityChildrenVector rowChildren = m_rows[row]->children();
481d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        cells.appendVector(rowChildren);
4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
48402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
485bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)unsigned AXTable::columnCount()
4865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    updateChildrenIfNecessary();
48802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
48902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    return m_columns.size();
4905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
49102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
492bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)unsigned AXTable::rowCount()
4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    updateChildrenIfNecessary();
49502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_rows.size();
4975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
499bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)AXTableCell* AXTable::cellForColumnAndRow(unsigned column, unsigned row)
5005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    updateChildrenIfNecessary();
502926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (column >= columnCount() || row >= rowCount())
503926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return 0;
50402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
505926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // Iterate backwards through the rows in case the desired cell has a rowspan and exists in a previous row.
506926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    for (unsigned rowIndexCounter = row + 1; rowIndexCounter > 0; --rowIndexCounter) {
507926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        unsigned rowIndex = rowIndexCounter - 1;
508926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        AccessibilityChildrenVector children = m_rows[rowIndex]->children();
509926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // Since some cells may have colspans, we have to check the actual range of each
510926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // cell to determine which is the right one.
511926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        for (unsigned colIndexCounter = std::min(static_cast<unsigned>(children.size()), column + 1); colIndexCounter > 0; --colIndexCounter) {
512926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            unsigned colIndex = colIndexCounter - 1;
513bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            AXObject* child = children[colIndex].get();
514926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            ASSERT(child->isTableCell());
515926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if (!child->isTableCell())
516926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                continue;
51702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
518926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            pair<unsigned, unsigned> columnRange;
519926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            pair<unsigned, unsigned> rowRange;
520bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)            AXTableCell* tableCellChild = toAXTableCell(child);
521926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            tableCellChild->columnIndexRange(columnRange);
522926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            tableCellChild->rowIndexRange(rowRange);
52302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
524926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            if ((column >= columnRange.first && column < (columnRange.first + columnRange.second))
525926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                && (row >= rowRange.first && row < (rowRange.first + rowRange.second)))
526926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                return tableCellChild;
5275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
5285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
52902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
530926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return 0;
5315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
533bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)AccessibilityRole AXTable::roleValue() const
5345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
535bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    if (!isAXTable())
536bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        return AXRenderObject::roleValue();
5375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return TableRole;
5395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
54002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
541bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)bool AXTable::computeAccessibilityIsIgnored() const
5425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
543bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    AXObjectInclusion decision = defaultObjectInclusion();
5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (decision == IncludeObject)
5455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
5465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (decision == IgnoreObject)
5475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
54802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
549bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    if (!isAXTable())
550bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        return AXRenderObject::computeAccessibilityIsIgnored();
55102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return false;
5535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
55402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
555bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)String AXTable::title() const
5565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
557bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    if (!isAXTable())
558bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        return AXRenderObject::title();
55902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    String title;
5615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!m_renderer)
5625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return title;
563e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
5645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // see if there is a caption
5655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Node* tableElement = m_renderer->node();
566d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (isHTMLTableElement(tableElement)) {
567e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        HTMLTableCaptionElement* caption = toHTMLTableElement(tableElement)->caption();
5685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (caption)
5695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            title = caption->innerText();
5705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
571e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
57202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    // try the standard
5735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (title.isEmpty())
574bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        title = AXRenderObject::title();
57502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return title;
5775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
579c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink
580