Пример #1
0
AccessibilityTableCell* AccessibilityTable::cellForColumnAndRow(unsigned column, unsigned row)
{
    updateChildrenIfNecessary();
    if (column >= columnCount() || row >= rowCount())
        return 0;
    
    // Iterate backwards through the rows in case the desired cell has a rowspan and exists in a previous row.
    for (unsigned rowIndexCounter = row + 1; rowIndexCounter > 0; --rowIndexCounter) {
        unsigned rowIndex = rowIndexCounter - 1;
        AccessibilityChildrenVector children = m_rows[rowIndex]->children();
        // Since some cells may have colspans, we have to check the actual range of each
        // cell to determine which is the right one.
        for (unsigned colIndexCounter = std::min(static_cast<unsigned>(children.size()), column + 1); colIndexCounter > 0; --colIndexCounter) {
            unsigned colIndex = colIndexCounter - 1;
            AccessibilityObject* child = children[colIndex].get();
            ASSERT(child->isTableCell());
            if (!child->isTableCell())
                continue;
            
            pair<unsigned, unsigned> columnRange;
            pair<unsigned, unsigned> rowRange;
            AccessibilityTableCell* tableCellChild = toAccessibilityTableCell(child);
            tableCellChild->columnIndexRange(columnRange);
            tableCellChild->rowIndexRange(rowRange);
            
            if ((column >= columnRange.first && column < (columnRange.first + columnRange.second))
                && (row >= rowRange.first && row < (rowRange.first + rowRange.second)))
                return tableCellChild;
        }
    }
    
    return 0;
}
Пример #2
0
void AccessibilityNodeObject::addChildren()
{
    // If the need to add more children in addition to existing children arises, 
    // childrenChanged should have been called, leaving the object with no children.
    ASSERT(!m_haveChildren); 
    
    if (!m_node)
        return;

    m_haveChildren = true;

    // The only time we add children from the DOM tree to a node with a renderer is when it's a canvas.
    if (renderer() && !m_node->hasTagName(canvasTag))
        return;
    
    for (Node* child = m_node->firstChild(); child; child = child->nextSibling()) {
        RefPtr<AccessibilityObject> obj = axObjectCache()->getOrCreate(child);
        obj->clearChildren();
        if (obj->accessibilityIsIgnored()) {
            AccessibilityChildrenVector children = obj->children();
            size_t length = children.size();
            for (size_t i = 0; i < length; ++i)
                m_children.append(children[i]);
        } else {
            ASSERT(obj->parentObject() == this);
            m_children.append(obj);
        }
    }
}
Пример #3
0
void AccessibilityARIAGridCell::rowIndexRange(pair<unsigned, unsigned>& rowRange)
{
    AccessibilityObject* parent = parentObjectUnignored();
    if (!parent)
        return;

    if (parent->isTableRow()) {
        // We already got a table row, use its API.
        rowRange.first = static_cast<AccessibilityTableRow*>(parent)->rowIndex();
    } else if (parent->isAccessibilityTable()) {
        // We reached the parent table, so we need to inspect its
        // children to determine the row index for the cell in it.
        unsigned columnCount = static_cast<AccessibilityTable*>(parent)->columnCount();
        if (!columnCount)
            return;

        AccessibilityChildrenVector siblings = parent->children();
        unsigned childrenSize = siblings.size();
        for (unsigned k = 0; k < childrenSize; ++k) {
            if (siblings[k].get() == this) {
                rowRange.first = k / columnCount;
                break;
            }
        }
    }

    // as far as I can tell, grid cells cannot span rows
    rowRange.second = 1;
}
void AccessibilityListBox::setSelectedChildren(AccessibilityChildrenVector& children)
{
    if (!canSetSelectedChildrenAttribute())
        return;
    
    Node* selectNode = m_renderer->node();
    if (!selectNode)
        return;
    
    // disable any selected options
    unsigned length = m_children.size();
    for (unsigned i = 0; i < length; i++) {
        AccessibilityListBoxOption* listBoxOption = static_cast<AccessibilityListBoxOption*>(m_children[i].get());
        if (listBoxOption->isSelected())
            listBoxOption->setSelected(false);
    }
    
    length = children.size();
    for (unsigned i = 0; i < length; i++) {
        AccessibilityObject* obj = children[i].get();
        if (obj->roleValue() != ListBoxOptionRole)
            continue;
                
        static_cast<AccessibilityListBoxOption*>(obj)->setSelected(true);
    }
}
Пример #5
0
void AccessibilityObject::accessibleObjectsWithAccessibilitySearchPredicate(AccessibilitySearchPredicate* axSearchPredicate, AccessibilityChildrenVector& axResults)
{
    ASSERT(AXObjectCache::accessibilityEnabled());
    
    if (!axSearchPredicate)
        return;
    
    AccessibilityChildrenVector axChildren;
    if (axSearchPredicate->axContainerObject)
        axChildren.append(axSearchPredicate->axContainerObject);
    
    bool isSearchDirectionNext = (axSearchPredicate->axSearchDirection == SearchDirectionNext);
    bool didFindAXStartObject = (!axSearchPredicate->axStartObject);
    
    // FIXME: Iterate the AccessibilityObject cache creating and adding objects if nessesary.
    while (!axChildren.isEmpty() && axResults.size() < axSearchPredicate->resultsLimit) {
        AccessibilityObject* axChild = axChildren.last().get();
        axChildren.removeLast();
        
        if (didFindAXStartObject) {
            if (isAccessibilityObjectSearchMatch(axChild, axSearchPredicate)
                && isAccessibilityTextSearchMatch(axChild, axSearchPredicate))
                axResults.append(axChild);
        } else if (axChild == axSearchPredicate->axStartObject)
            didFindAXStartObject = true;
        
        AccessibilityChildrenVector axGrandchildren = axChild->children();
        unsigned axGrandchildrenSize = axChild->children().size();
        for (unsigned i = (isSearchDirectionNext) ? axGrandchildrenSize : 0; (isSearchDirectionNext) ? i > 0 : i < axGrandchildrenSize; (isSearchDirectionNext) ? i-- : i++)
            // FIXME: Handle attachments.
            axChildren.append(axGrandchildren.at((isSearchDirectionNext) ? i - 1 : i).get());
    }
}
AccessibilityObject* AccessibilityARIAGridRow::headerObject()
{
    AccessibilityChildrenVector rowChildren = children();
    unsigned childrenCount = rowChildren.size();
    for (unsigned i = 0; i < childrenCount; ++i) {
        AccessibilityObject* cell = rowChildren[i].get();
        if (cell->ariaRoleAttribute() == RowHeaderRole)
            return cell;
    }
    
    return 0;
}
Пример #7
0
void AccessibilityObject::findMatchingObjects(AccessibilitySearchCriteria* criteria, AccessibilityChildrenVector& results)
{
    ASSERT(criteria);
    
    if (!criteria)
        return;
    
    AccessibilityObject* startObject = criteria->startObject;
    AccessibilityChildrenVector searchStack;
    searchStack.append(this);
    
    bool isForward = criteria->searchDirection == SearchDirectionNext;
    bool didFindStartObject = !criteria->startObject;
    
    // FIXME: Iterate the AccessibilityObject cache creating and adding objects if nessesary.
    while (!searchStack.isEmpty()) {
        AccessibilityObject* searchObject = searchStack.last().get();
        searchStack.removeLast();
        
        if (didFindStartObject) {
            if (isAccessibilityObjectSearchMatch(searchObject, criteria) && isAccessibilityTextSearchMatch(searchObject, criteria)) {
                results.append(searchObject);
             
                // Enough results were found to stop searching.
                if (results.size() >= criteria->resultsLimit)
                    break;
            }
        } else if (searchObject == startObject)
            didFindStartObject = true;
        
        AccessibilityChildrenVector searchChildren = searchObject->children();
        size_t childrenSize = searchChildren.size();
        for (size_t i = isForward ? childrenSize : 0; isForward ? i > 0 : i < childrenSize; isForward ? i-- : i++) {
            // FIXME: Handle attachments.
            searchStack.append(searchChildren.at(isForward ? i - 1 : i).get());
        }
    }
}
void AccessibilityObject::ariaTreeItemContent(AccessibilityChildrenVector& result)
{
    // The ARIA tree item content are the item that are not other tree items or their containing groups.
    AccessibilityChildrenVector axChildren = children();
    unsigned count = axChildren.size();
    for (unsigned k = 0; k < count; ++k) {
        AccessibilityObject* obj = axChildren[k].get();
        AccessibilityRole role = obj->roleValue();
        if (role == TreeItemRole || role == GroupRole)
            continue;
        
        result.append(obj);
    }
}
void AccessibilityARIAGrid::addChildren()
{
    ASSERT(!m_haveChildren); 
    
    if (!isAccessibilityTable()) {
        AccessibilityRenderObject::addChildren();
        return;
    }
    
    m_haveChildren = true;
    if (!m_renderer)
        return;
    
    AXObjectCache* axCache = m_renderer->document()->axObjectCache();
    
    // add only rows that are labeled as aria rows
    HashSet<AccessibilityObject*> appendedRows;
    unsigned columnCount = 0;
    for (RefPtr<AccessibilityObject> child = firstChild(); child; child = child->nextSibling()) {

        if (!addTableCellChild(child.get(), appendedRows, columnCount)) {
            
            // in case the render tree doesn't match the expected ARIA hierarchy, look at the children
            if (!child->hasChildren())
                child->addChildren();

            // The children of this non-row will contain all non-ignored elements (recursing to find them). 
            // This allows the table to dive arbitrarily deep to find the rows.
            AccessibilityChildrenVector children = child->children();
            size_t length = children.size();
            for (size_t i = 0; i < length; ++i)
                addTableCellChild(children[i].get(), appendedRows, columnCount);
        }
    }
    
    // make the columns based on the number of columns in the first body
    for (unsigned i = 0; i < columnCount; ++i) {
        AccessibilityTableColumn* column = static_cast<AccessibilityTableColumn*>(axCache->getOrCreate(ColumnRole));
        column->setColumnIndex((int)i);
        column->setParent(this);
        m_columns.append(column);
        if (!column->accessibilityIsIgnored())
            m_children.append(column);
    }
    
    AccessibilityObject* headerContainerObject = headerContainer();
    if (headerContainerObject && !headerContainerObject->accessibilityIsIgnored())
        m_children.append(headerContainerObject);
}
void AccessibilityObject::ariaTreeRows(AccessibilityChildrenVector& result)
{
    AccessibilityChildrenVector axChildren = children();
    unsigned count = axChildren.size();
    for (unsigned k = 0; k < count; ++k) {
        AccessibilityObject* obj = axChildren[k].get();

        // Add tree items as the rows.
        if (obj->roleValue() == TreeItemRole)
            result.append(obj);

        // Now see if this item also has rows hiding inside of it.
        obj->ariaTreeRows(result);
    }
}
Пример #11
0
void AccessibilityObject::ariaTreeItemDisclosedRows(AccessibilityChildrenVector& result)
{
    AccessibilityChildrenVector axChildren = children();
    unsigned count = axChildren.size();
    for (unsigned k = 0; k < count; ++k) {
        AccessibilityObject* obj = axChildren[k].get();
        
        // Add tree items as the rows.
        if (obj->roleValue() == TreeItemRole)
            result.append(obj);
        // If it's not a tree item, then descend into the group to find more tree items.
        else 
            obj->ariaTreeRows(result);
    }    
}
void AccessibilityARIAGrid::addRowDescendant(AccessibilityObject* rowChild, HashSet<AccessibilityObject*>& appendedRows, unsigned& columnCount)
{
    if (!rowChild)
        return;

    if (!rowChild->isTableRow()) {
        // Although a "grid" should have rows as its direct descendants, if this is not a table row,
        // dive deeper into the descendants to try to find a valid row.
        AccessibilityChildrenVector children = rowChild->children();
        size_t length = children.size();
        for (size_t i = 0; i < length; ++i)
            addRowDescendant(children[i].get(), appendedRows, columnCount);
    } else
        addTableCellChild(rowChild, appendedRows, columnCount);
}
Пример #13
0
AccessibilityTableCell* AccessibilityARIAGrid::cellForColumnAndRow(unsigned column, unsigned row)
{
    if (!m_renderer)
        return 0;
    
    updateChildrenIfNecessary();
    
    if (column >= columnCount() || row >= rowCount())
        return 0;
    
    int intRow = (int)row;
    int intColumn = (int)column;

    pair<int, int> columnRange;
    pair<int, int> rowRange;
    
    // Iterate backwards through the rows in case the desired cell has a rowspan and exists
    // in a previous row.
    for (; intRow >= 0; --intRow) {
        AccessibilityObject* tableRow = m_rows[intRow].get();
        if (!tableRow)
            continue;
        
        AccessibilityChildrenVector children = tableRow->children();
        unsigned childrenLength = children.size();
        
        // Since some cells may have colspans, we have to check the actual range of each
        // cell to determine which is the right one.
        for (unsigned k = 0; k < childrenLength; ++k) {
            AccessibilityObject* child = children[k].get();
            if (!child->isTableCell()) 
                continue;
            
            AccessibilityTableCell* tableCellChild = static_cast<AccessibilityTableCell*>(child);
            tableCellChild->columnIndexRange(columnRange);
            tableCellChild->rowIndexRange(rowRange);
            
            if ((intColumn >= columnRange.first && intColumn < (columnRange.first + columnRange.second))
                && (intRow >= rowRange.first && intRow < (rowRange.first + rowRange.second)))
                return tableCellChild;
        }
    }

    return 0;
}
Пример #14
0
void AccessibilityAriaGridCell::columnIndexRange(pair<int, int>& columnRange)
{
    AccessibilityObject* parent = parentObjectUnignored();
    if (!parent || !parent->isTableRow())
        return;
    
    AccessibilityChildrenVector siblings = parent->children();
    unsigned childrenSize = siblings.size();
    for (unsigned k = 0; k < childrenSize; ++k) {
        if (siblings[k].get() == this) {
            columnRange.first = k;
            break;
        }
    }
    
    // as far as I can tell, grid cells cannot span columns
    columnRange.second = 1;    
}
AccessibilityObject* AccessibilityTableColumn::headerObject()
{
    if (!m_parent)
        return 0;
    
    RenderObject* renderer = m_parent->renderer();
    if (!renderer)
        return 0;
    
    if (!m_parent->isAccessibilityTable())
        return 0;
    
    AccessibilityTable* parentTable = toAccessibilityTable(m_parent);
    if (parentTable->isAriaTable()) {
        AccessibilityChildrenVector rowChildren = children();
        unsigned childrenCount = rowChildren.size();
        for (unsigned i = 0; i < childrenCount; ++i) {
            AccessibilityObject* cell = rowChildren[i].get();
            if (cell->ariaRoleAttribute() == ColumnHeaderRole)
                return cell;
        }
        
        return 0;
    }

    if (!renderer->isTable())
        return 0;
    
    RenderTable* table = toRenderTable(renderer);
    
    AccessibilityObject* headerObject = 0;
    
    // try the <thead> section first. this doesn't require th tags
    headerObject = headerObjectForSection(table->header(), false);

    if (headerObject)
        return headerObject;
    
    // now try for <th> tags in the first body
    headerObject = headerObjectForSection(table->firstBody(), true);

    return headerObject;
}
Пример #16
0
AccessibilityObject* AccessibilityTableRow::headerObject()
{
    AccessibilityChildrenVector rowChildren = children();
    if (!rowChildren.size())
        return 0;
    
    // check the first element in the row to see if it is a TH element
    AccessibilityObject* cell = rowChildren[0].get();
    if (!cell->isTableCell())
        return 0;
    
    RenderObject* cellRenderer = static_cast<AccessibilityTableCell*>(cell)->renderer();
    if (!cellRenderer)
        return 0;
    
    Node* cellNode = cellRenderer->element();
    if (!cellNode || !cellNode->hasTagName(thTag))
        return 0;
    
    return cell;
}
AccessibilityTableCell* AccessibilityARIAGrid::cellForColumnAndRow(unsigned column, unsigned row)
{
    if (!m_renderer)
        return 0;
    
    updateChildrenIfNecessary();
    
    if (column >= columnCount() || row >= rowCount())
        return 0;
    
    AccessibilityObject* tableRow = m_rows[row].get();
    if (!tableRow)
        return 0;
    
    AccessibilityChildrenVector children = tableRow->children();
    // in case this row had fewer columns than other rows
    AccessibilityObject* tableCell = 0;
    if (column >= children.size())
        return 0;

    tableCell = children[column].get();
    return static_cast<AccessibilityTableCell*>(tableCell);
}
Пример #18
0
AXObject* AXTableRow::headerObject()
{
    if (!m_renderer || !m_renderer->isTableRow())
        return 0;

    AccessibilityChildrenVector rowChildren = children();
    if (!rowChildren.size())
        return 0;

    // check the first element in the row to see if it is a TH element
    AXObject* cell = rowChildren[0].get();
    if (!cell->isTableCell())
        return 0;

    RenderObject* cellRenderer = toAXTableCell(cell)->renderer();
    if (!cellRenderer)
        return 0;

    Node* cellNode = cellRenderer->node();
    if (!cellNode || !cellNode->hasTagName(thTag))
        return 0;

    return cell;
}