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