void AXListBox::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++) { AXListBoxOption* listBoxOption = toAXListBoxOption(m_children[i].get()); if (listBoxOption->isSelected()) listBoxOption->setSelected(false); } length = children.size(); for (unsigned i = 0; i < length; i++) { AXObject* obj = children[i].get(); if (obj->roleValue() != ListBoxOptionRole) continue; toAXListBoxOption(obj)->setSelected(true); } }
void InspectorAccessibilityAgent::getAXNode(ErrorString* errorString, int nodeId, RefPtr<AXNode>& accessibilityNode) { Frame* mainFrame = m_page->mainFrame(); if (!mainFrame->isLocalFrame()) { *errorString = "Can't inspect out of process frames yet"; return; } InspectorDOMAgent* domAgent = toLocalFrame(mainFrame)->instrumentingAgents()->inspectorDOMAgent(); if (!domAgent) { *errorString = "DOM agent must be enabled"; return; } Node* node = domAgent->assertNode(errorString, nodeId); if (!node) return; Document& document = node->document(); OwnPtr<ScopedAXObjectCache> cache = ScopedAXObjectCache::create(document); AXObjectCacheImpl* cacheImpl = toAXObjectCacheImpl(cache->get()); AXObject* axObject = cacheImpl->getOrCreate(node); if (!axObject || axObject->accessibilityIsIgnored()) { accessibilityNode = buildObjectForIgnoredNode(node, axObject, cacheImpl); return; } RefPtr<TypeBuilder::Array<AXProperty>> properties = TypeBuilder::Array<AXProperty>::create(); fillLiveRegionProperties(axObject, properties); fillGlobalStates(axObject, properties); fillWidgetProperties(axObject, properties); fillWidgetStates(axObject, properties); fillRelationships(axObject, properties); accessibilityNode = buildObjectForNode(node, axObject, cacheImpl, properties); }
const AtomicString& AXObjectCacheImpl::computedRoleForNode(Node* node) { AXObject* obj = getOrCreate(node); if (!obj) return AXObject::roleName(UnknownRole); return AXObject::roleName(obj->roleValue()); }
void AXObjectCacheImpl::handleEditableTextContentChanged(Node* node) { AXObject* obj = get(node); while (obj && !obj->isNativeTextControl() && !obj->isNonNativeTextControl()) obj = obj->parentObject(); postNotification(obj, AXObjectCache::AXValueChanged); }
bool AXTableCell::isTableCell() const { AXObject* parent = parentObjectUnignored(); if (!parent || !parent->isTableRow()) return false; return true; }
AXObject* AXListBox::elementAccessibilityHitTest(const IntPoint& point) const { // the internal HTMLSelectElement methods for returning a listbox option at a point // ignore optgroup elements. if (!m_renderer) return 0; Node* node = m_renderer->node(); if (!node) return 0; LayoutRect parentRect = elementRect(); AXObject* listBoxOption = 0; unsigned length = m_children.size(); for (unsigned i = 0; i < length; i++) { LayoutRect rect = toRenderListBox(m_renderer)->itemBoundingBoxRect(parentRect.location(), i); // The cast to HTMLElement below is safe because the only other possible listItem type // would be a WMLElement, but WML builds don't use accessibility features at all. if (rect.contains(point)) { listBoxOption = m_children[i].get(); break; } } if (listBoxOption && !listBoxOption->accessibilityIsIgnored()) return listBoxOption; return axObjectCache()->getOrCreate(m_renderer); }
AXObject* AXObjectCache::focusedImageMapUIElement(HTMLAreaElement* areaElement) { // Find the corresponding accessibility object for the HTMLAreaElement. This should be // in the list of children for its corresponding image. if (!areaElement) return 0; HTMLImageElement* imageElement = areaElement->imageElement(); if (!imageElement) return 0; AXObject* axRenderImage = areaElement->document().axObjectCache()->getOrCreate(imageElement); if (!axRenderImage) return 0; AXObject::AccessibilityChildrenVector imageChildren = axRenderImage->children(); unsigned count = imageChildren.size(); for (unsigned k = 0; k < count; ++k) { AXObject* child = imageChildren[k].get(); if (!child->isImageMapLink()) continue; if (toAXImageMapLink(child)->areaElement() == areaElement) return child; } return 0; }
AXTableCell* AXTable::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; const auto& 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; AXObject* child = children[colIndex].get(); if (!child->isTableCell()) continue; std::pair<unsigned, unsigned> columnRange; std::pair<unsigned, unsigned> rowRange; AXTableCell* tableCellChild = toAXTableCell(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; }
Document* AXScrollbar::document() const { AXObject* parent = parentObject(); if (!parent) return 0; return parent->document(); }
void AXARIAGridCell::rowIndexRange(pair<unsigned, unsigned>& rowRange) { AXObject* parent = parentObjectUnignored(); if (!parent) return; if (parent->isTableRow()) { // We already got a table row, use its API. rowRange.first = toAXTableRow(parent)->rowIndex(); } else if (parent->isAXTable()) { // We reached the parent table, so we need to inspect its // children to determine the row index for the cell in it. unsigned columnCount = toAXTable(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; }
AXObject* AXObjectCacheImpl::focusedUIElementForPage(const Page* page) { if (!page->settings().accessibilityEnabled()) return 0; // Cross-process accessibility is not yet implemented. if (!page->focusController().focusedOrMainFrame()->isLocalFrame()) return 0; // get the focused node in the page Document* focusedDocument = toLocalFrame(page->focusController().focusedOrMainFrame())->document(); Node* focusedNode = focusedDocument->focusedElement(); if (!focusedNode) focusedNode = focusedDocument; if (isHTMLAreaElement(*focusedNode)) return focusedImageMapUIElement(toHTMLAreaElement(focusedNode)); AXObject* obj = toAXObjectCacheImpl(focusedNode->document().axObjectCache())->getOrCreate(focusedNode); if (!obj) return 0; if (obj->shouldFocusActiveDescendant()) { if (AXObject* descendant = obj->activeDescendant()) obj = descendant; } // the HTML element, for example, is focusable but has an AX object that is ignored if (obj->accessibilityIsIgnored()) obj = obj->parentObjectUnignored(); return obj; }
AXObject* AXObjectCache::focusedUIElementForPage(const Page* page) { if (!gAccessibilityEnabled) return 0; // get the focused node in the page Document* focusedDocument = page->focusController().focusedOrMainFrame()->document(); Node* focusedNode = focusedDocument->focusedElement(); if (!focusedNode) focusedNode = focusedDocument; if (focusedNode->hasTagName(areaTag)) return focusedImageMapUIElement(toHTMLAreaElement(focusedNode)); AXObject* obj = focusedNode->document().axObjectCache()->getOrCreate(focusedNode); if (!obj) return 0; if (obj->shouldFocusActiveDescendant()) { if (AXObject* descendant = obj->activeDescendant()) obj = descendant; } // the HTML element, for example, is focusable but has an AX object that is ignored if (obj->accessibilityIsIgnored()) obj = obj->parentObjectUnignored(); return obj; }
void AXObject::scrollToGlobalPoint(const IntPoint& globalPoint) const { // Search up the parent chain and create a vector of all scrollable parent objects // and ending with this object itself. Vector<const AXObject*> objects; AXObject* parentObject; for (parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) { if (parentObject->getScrollableAreaIfScrollable()) objects.prepend(parentObject); } objects.append(this); // Start with the outermost scrollable (the main window) and try to scroll the // next innermost object to the given point. int offsetX = 0, offsetY = 0; IntPoint point = globalPoint; size_t levels = objects.size() - 1; for (size_t i = 0; i < levels; i++) { const AXObject* outer = objects[i]; const AXObject* inner = objects[i + 1]; ScrollableArea* scrollableArea = outer->getScrollableAreaIfScrollable(); LayoutRect innerRect = inner->isAXScrollView() ? inner->parentObject()->elementRect() : inner->elementRect(); LayoutRect objectRect = innerRect; IntPoint scrollPosition = scrollableArea->scrollPosition(); // Convert the object rect into local coordinates. objectRect.move(offsetX, offsetY); if (!outer->isAXScrollView()) objectRect.move(scrollPosition.x(), scrollPosition.y()); int desiredX = computeBestScrollOffset( 0, objectRect.x(), objectRect.maxX(), objectRect.x(), objectRect.maxX(), point.x(), point.x()); int desiredY = computeBestScrollOffset( 0, objectRect.y(), objectRect.maxY(), objectRect.y(), objectRect.maxY(), point.y(), point.y()); outer->scrollTo(IntPoint(desiredX, desiredY)); if (outer->isAXScrollView() && !inner->isAXScrollView()) { // If outer object we just scrolled is a scroll view (main window or iframe) but the // inner object is not, keep track of the coordinate transformation to apply to // future nested calculations. scrollPosition = scrollableArea->scrollPosition(); offsetX -= (scrollPosition.x() + point.x()); offsetY -= (scrollPosition.y() + point.y()); point.move(scrollPosition.x() - innerRect.x(), scrollPosition.y() - innerRect.y()); } else if (inner->isAXScrollView()) { // Otherwise, if the inner object is a scroll view, reset the coordinate transformation. offsetX = 0; offsetY = 0; } } }
void AXObjectCacheImpl::listboxActiveIndexChanged(HTMLSelectElement* select) { AXObject* obj = get(select); if (!obj || !obj->isAXListBox()) return; toAXListBox(obj)->activeIndexChanged(); }
bool AXARIAGridRow::isARIATreeGridRow() const { AXObject* parent = parentTable(); if (!parent) return false; return parent->ariaRoleAttribute() == TreeGridRole; }
void AXObjectCacheImpl::setCanvasObjectBounds(Element* element, const LayoutRect& rect) { AXObject* obj = getOrCreate(element); if (!obj) return; obj->setElementRect(rect); }
void AXObjectCacheImpl::handleScrollPositionChanged(FrameView* frameView) { // Prefer to fire the scroll position changed event on the frame view's child web area, if possible. AXObject* targetAXObject = getOrCreate(frameView); if (targetAXObject && !targetAXObject->children().isEmpty()) targetAXObject = targetAXObject->children()[0].get(); postPlatformNotification(targetAXObject, AXScrollPositionChanged); }
void AXObjectCacheImpl::didHideMenuListPopup(LayoutMenuList* menuList) { AXObject* obj = get(menuList); if (!obj || !obj->isMenuList()) return; toAXMenuList(obj)->didHidePopup(); }
void AXObjectCacheImpl::handleUpdateActiveMenuOption(LayoutMenuList* menuList, int optionIndex) { AXObject* obj = get(menuList); if (!obj || !obj->isMenuList()) return; toAXMenuList(obj)->didUpdateActiveOption(optionIndex); }
AXObject* AXTableRow::parentTable() const { AXObject* parent = parentObjectUnignored(); if (!parent || !parent->isAXTable()) return 0; return parent; }
String AXObjectCacheImpl::computedNameForNode(Node* node) { AXObject* obj = getOrCreate(node); if (!obj) return ""; return obj->computedName(); }
AXObject* AXObject::parentObjectUnignored() const { AXObject* parent; for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) { } return parent; }
bool AXTableRow::isTableRow() const { AXObject* table = parentTable(); if (!table || !table->isAXTable()) return false; return true; }
bool AXScrollView::computeAccessibilityIsIgnored() const { AXObject* webArea = webAreaObject(); if (!webArea) return true; return webArea->accessibilityIsIgnored(); }
int AXTable::tableLevel() const { int level = 0; for (AXObject* obj = static_cast<AXObject*>(const_cast<AXTable*>(this)); obj; obj = obj->parentObject()) { if (obj->isAXTable()) ++level; } return level; }
void AXScrollView::addChildren() { ASSERT(!m_haveChildren); m_haveChildren = true; AXObject* webArea = webAreaObject(); if (webArea && !webArea->accessibilityIsIgnored()) m_children.append(webArea); updateScrollbars(); }
void AXObjectCacheImpl::handleAriaSelectedChanged(Node* node) { AXObject* obj = get(node); if (!obj) return; postNotification(obj, AXCheckedStateChanged); AXObject* listbox = obj->parentObjectUnignored(); if (listbox && listbox->roleValue() == ListBoxRole) postNotification(listbox, AXSelectedChildrenChanged); }
AXObject* AXARIAGridRow::headerObject() { AccessibilityChildrenVector rowChildren = children(); unsigned childrenCount = rowChildren.size(); for (unsigned i = 0; i < childrenCount; ++i) { AXObject* cell = rowChildren[i].get(); if (cell->ariaRoleAttribute() == RowHeaderRole) return cell; } return 0; }
AXMenuListOption* AXMenuListPopup::menuListOptionAXObject(HTMLElement* element) const { ASSERT(element); if (!isHTMLOptionElement(*element)) return 0; AXObject* object = axObjectCache().getOrCreate(element); if (!object || !object->isMenuListOption()) return 0; return toAXMenuListOption(object); }
AXObjectCache::~AXObjectCache() { m_notificationPostTimer.stop(); HashMap<AXID, RefPtr<AXObject> >::iterator end = m_objects.end(); for (HashMap<AXID, RefPtr<AXObject> >::iterator it = m_objects.begin(); it != end; ++it) { AXObject* obj = (*it).value.get(); detachWrapper(obj); obj->detach(); removeAXID(obj); } }