/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE.Chromium file. #include "browser_accessibility_qt.h" #if QT_CONFIG(accessibility) #include "ui/accessibility/ax_enums.mojom.h" #include "browser_accessibility_manager_qt.h" #include "qtwebenginecoreglobal_p.h" #include "type_conversion.h" using namespace blink; using QtWebEngineCore::toQt; namespace content { // static BrowserAccessibility *BrowserAccessibility::Create() { #if QT_CONFIG(accessibility) return new BrowserAccessibilityQt(); #else return nullptr; #endif // QT_CONFIG(accessibility) } const BrowserAccessibilityQt *ToBrowserAccessibilityQt(const BrowserAccessibility *obj) { return static_cast(obj); } QAccessibleInterface *toQAccessibleInterface(BrowserAccessibility *obj) { return static_cast(obj); } BrowserAccessibilityQt::BrowserAccessibilityQt() { QAccessible::registerAccessibleInterface(this); } bool BrowserAccessibilityQt::isValid() const { auto managerQt = static_cast(manager_); return managerQt && managerQt->isValid(); } QObject *BrowserAccessibilityQt::object() const { return nullptr; } QAccessibleInterface *BrowserAccessibilityQt::childAt(int x, int y) const { for (int i = 0; i < childCount(); ++i) { QAccessibleInterface *childIface = child(i); Q_ASSERT(childIface); if (childIface->rect().contains(x,y)) return childIface; } return nullptr; } void *BrowserAccessibilityQt::interface_cast(QAccessible::InterfaceType type) { switch (type) { case QAccessible::ActionInterface: if (!actionNames().isEmpty()) return static_cast(this); break; case QAccessible::TextInterface: if (HasState(ax::mojom::State::kEditable)) return static_cast(this); break; case QAccessible::ValueInterface: { QAccessible::Role r = role(); if (r == QAccessible::ProgressBar || r == QAccessible::Slider || r == QAccessible::ScrollBar || r == QAccessible::SpinBox) return static_cast(this); break; } case QAccessible::TableInterface: { QAccessible::Role r = role(); if (r == QAccessible::Table || r == QAccessible::List || r == QAccessible::Tree) return static_cast(this); break; } case QAccessible::TableCellInterface: { QAccessible::Role r = role(); if (r == QAccessible::Cell || r == QAccessible::ListItem || r == QAccessible::TreeItem) return static_cast(this); break; } default: break; } return nullptr; } QAccessibleInterface *BrowserAccessibilityQt::parent() const { BrowserAccessibility *p = PlatformGetParent(); if (p) return static_cast(p); return static_cast(manager())->rootParentAccessible(); } QAccessibleInterface *BrowserAccessibilityQt::child(int index) const { return static_cast(BrowserAccessibility::PlatformGetChild(index)); } QAccessibleInterface *BrowserAccessibilityQt::focusChild() const { if (state().focused) return const_cast(this); for (int i = 0; i < childCount(); ++i) { if (QAccessibleInterface *iface = child(i)->focusChild()) return iface; } return nullptr; } int BrowserAccessibilityQt::childCount() const { return PlatformChildCount(); } int BrowserAccessibilityQt::indexOfChild(const QAccessibleInterface *iface) const { const BrowserAccessibilityQt *child = static_cast(iface); return const_cast(child)->GetIndexInParent(); } QString BrowserAccessibilityQt::text(QAccessible::Text t) const { switch (t) { case QAccessible::Name: return toQt(GetStringAttribute(ax::mojom::StringAttribute::kName)); case QAccessible::Description: return toQt(GetStringAttribute(ax::mojom::StringAttribute::kDescription)); case QAccessible::Value: return toQt(GetStringAttribute(ax::mojom::StringAttribute::kValue)); case QAccessible::Accelerator: return toQt(GetStringAttribute(ax::mojom::StringAttribute::kKeyShortcuts)); default: break; } return QString(); } void BrowserAccessibilityQt::setText(QAccessible::Text t, const QString &text) { } QRect BrowserAccessibilityQt::rect() const { if (!manager()) // needed implicitly by GetScreenBoundsRect() return QRect(); gfx::Rect bounds = GetUnclippedScreenBoundsRect(); return QRect(bounds.x(), bounds.y(), bounds.width(), bounds.height()); } QAccessible::Role BrowserAccessibilityQt::role() const { switch (GetRole()) { case ax::mojom::Role::kNone: case ax::mojom::Role::kUnknown: return QAccessible::NoRole; // Internal roles (matching auralinux and win) case ax::mojom::Role::kKeyboard: case ax::mojom::Role::kIgnored: case ax::mojom::Role::kImeCandidate: case ax::mojom::Role::kPresentational: return QAccessible::NoRole; // Used by Chromium to distinguish between the root of the tree // for this page, and a web area for a frame within this page. case ax::mojom::Role::kWebView: case ax::mojom::Role::kRootWebArea: // not sure if we need to make a diff here, but this seems common return QAccessible::WebDocument; // These roles all directly correspond to blink accessibility roles, // keep these alphabetical. case ax::mojom::Role::kAbbr: return QAccessible::StaticText; case ax::mojom::Role::kAlert: case ax::mojom::Role::kAlertDialog: return QAccessible::AlertMessage; case ax::mojom::Role::kAnchor: return QAccessible::Link; case ax::mojom::Role::kApplication: return QAccessible::Document; // returning Application here makes Qt return the top level app object case ax::mojom::Role::kArticle: return QAccessible::Section; case ax::mojom::Role::kAudio: return QAccessible::Sound; case ax::mojom::Role::kBanner: return QAccessible::Section; case ax::mojom::Role::kBlockquote: return QAccessible::Section; case ax::mojom::Role::kButton: return QAccessible::Button; case ax::mojom::Role::kCanvas: return QAccessible::Canvas; case ax::mojom::Role::kCaption: return QAccessible::Heading; case ax::mojom::Role::kCaret: return QAccessible::NoRole; // FIXME: https://codereview.chromium.org/2781613003 case ax::mojom::Role::kCell: return QAccessible::Cell; case ax::mojom::Role::kCheckBox: return QAccessible::CheckBox; case ax::mojom::Role::kClient: return QAccessible::Client; case ax::mojom::Role::kCode: return QAccessible::StaticText; case ax::mojom::Role::kColorWell: return QAccessible::ColorChooser; case ax::mojom::Role::kColumn: return QAccessible::Column; case ax::mojom::Role::kColumnHeader: return QAccessible::ColumnHeader; case ax::mojom::Role::kComboBoxGrouping: case ax::mojom::Role::kComboBoxMenuButton: case ax::mojom::Role::kTextFieldWithComboBox: return QAccessible::ComboBox; case ax::mojom::Role::kComplementary: return QAccessible::ComplementaryContent; case ax::mojom::Role::kComment: return QAccessible::Section; case ax::mojom::Role::kContentDeletion: case ax::mojom::Role::kContentInsertion: return QAccessible::Grouping; case ax::mojom::Role::kContentInfo: return QAccessible::Section; case ax::mojom::Role::kDate: case ax::mojom::Role::kDateTime: return QAccessible::Clock; case ax::mojom::Role::kDefinition: return QAccessible::Paragraph; case ax::mojom::Role::kDescriptionList: return QAccessible::List; case ax::mojom::Role::kDescriptionListDetail: return QAccessible::Paragraph; case ax::mojom::Role::kDescriptionListTerm: return QAccessible::ListItem; case ax::mojom::Role::kDetails: return QAccessible::Grouping; case ax::mojom::Role::kDesktop: return QAccessible::Pane; case ax::mojom::Role::kDialog: return QAccessible::Dialog; case ax::mojom::Role::kDirectory: return QAccessible::List; case ax::mojom::Role::kDisclosureTriangle: return QAccessible::Button; case ax::mojom::Role::kGenericContainer: return QAccessible::Section; case ax::mojom::Role::kDocCover: return QAccessible::Graphic; case ax::mojom::Role::kDocBackLink: case ax::mojom::Role::kDocBiblioRef: case ax::mojom::Role::kDocGlossRef: case ax::mojom::Role::kDocNoteRef: return QAccessible::Link; case ax::mojom::Role::kDocBiblioEntry: case ax::mojom::Role::kDocEndnote: case ax::mojom::Role::kDocFootnote: return QAccessible::ListItem; case ax::mojom::Role::kDocPageBreak: return QAccessible::Separator; case ax::mojom::Role::kDocAbstract: case ax::mojom::Role::kDocAcknowledgments: case ax::mojom::Role::kDocAfterword: case ax::mojom::Role::kDocAppendix: case ax::mojom::Role::kDocBibliography: case ax::mojom::Role::kDocChapter: case ax::mojom::Role::kDocColophon: case ax::mojom::Role::kDocConclusion: case ax::mojom::Role::kDocCredit: case ax::mojom::Role::kDocCredits: case ax::mojom::Role::kDocDedication: case ax::mojom::Role::kDocEndnotes: case ax::mojom::Role::kDocEpigraph: case ax::mojom::Role::kDocEpilogue: case ax::mojom::Role::kDocErrata: case ax::mojom::Role::kDocExample: case ax::mojom::Role::kDocForeword: case ax::mojom::Role::kDocGlossary: case ax::mojom::Role::kDocIndex: case ax::mojom::Role::kDocIntroduction: case ax::mojom::Role::kDocNotice: return QAccessible::Section; case ax::mojom::Role::kDocPageFooter: return QAccessible::Footer; case ax::mojom::Role::kDocPageHeader: return QAccessible::Heading; case ax::mojom::Role::kDocPageList: case ax::mojom::Role::kDocPart: case ax::mojom::Role::kDocPreface: case ax::mojom::Role::kDocPrologue: case ax::mojom::Role::kDocPullquote: case ax::mojom::Role::kDocQna: return QAccessible::Section; case ax::mojom::Role::kDocSubtitle: return QAccessible::Heading; case ax::mojom::Role::kDocTip: case ax::mojom::Role::kDocToc: return QAccessible::Section; case ax::mojom::Role::kDocument: return QAccessible::Document; case ax::mojom::Role::kEmbeddedObject: return QAccessible::Grouping; case ax::mojom::Role::kEmphasis: return QAccessible::StaticText; case ax::mojom::Role::kFeed: return QAccessible::Section; case ax::mojom::Role::kFigcaption: return QAccessible::Heading; case ax::mojom::Role::kFigure: return QAccessible::Section; case ax::mojom::Role::kFooter: // CORE-AAM recommends LANDMARK instead of FOOTER. return QAccessible::Section; case ax::mojom::Role::kFooterAsNonLandmark: return QAccessible::Section; case ax::mojom::Role::kForm: return QAccessible::Form; case ax::mojom::Role::kGraphicsDocument: return QAccessible::Document; case ax::mojom::Role::kGraphicsObject: return QAccessible::Pane; case ax::mojom::Role::kGraphicsSymbol: return QAccessible::Graphic; case ax::mojom::Role::kGrid: return QAccessible::Table; case ax::mojom::Role::kGroup: return QAccessible::Grouping; case ax::mojom::Role::kHeader: case ax::mojom::Role::kHeaderAsNonLandmark: return QAccessible::Section; case ax::mojom::Role::kHeading: return QAccessible::Heading; case ax::mojom::Role::kIframe: return QAccessible::WebDocument; case ax::mojom::Role::kIframePresentational: return QAccessible::Grouping; case ax::mojom::Role::kImage: return QAccessible::Graphic; case ax::mojom::Role::kImageMap: return QAccessible::Document; case ax::mojom::Role::kInlineTextBox: return QAccessible::StaticText; case ax::mojom::Role::kInputTime: return QAccessible::SpinBox; case ax::mojom::Role::kLabelText: return QAccessible::StaticText; case ax::mojom::Role::kLayoutTable: case ax::mojom::Role::kLayoutTableCell: case ax::mojom::Role::kLayoutTableRow: return QAccessible::Section; case ax::mojom::Role::kLegend: return QAccessible::StaticText; case ax::mojom::Role::kLineBreak: return QAccessible::Separator; case ax::mojom::Role::kLink: return QAccessible::Link; case ax::mojom::Role::kList: return QAccessible::List; case ax::mojom::Role::kListBox: return QAccessible::ComboBox; case ax::mojom::Role::kListBoxOption: return QAccessible::ListItem; case ax::mojom::Role::kListItem: return QAccessible::ListItem; case ax::mojom::Role::kListGrid: return QAccessible::List; case ax::mojom::Role::kListMarker: return QAccessible::StaticText; case ax::mojom::Role::kLog: return QAccessible::Section; case ax::mojom::Role::kMain: return QAccessible::Grouping; case ax::mojom::Role::kMark: return QAccessible::StaticText; case ax::mojom::Role::kMarquee: return QAccessible::Section; case ax::mojom::Role::kMath: return QAccessible::Equation; case ax::mojom::Role::kMenu: return QAccessible::PopupMenu; case ax::mojom::Role::kMenuBar: return QAccessible::MenuBar; case ax::mojom::Role::kMenuItem: return QAccessible::MenuItem; case ax::mojom::Role::kMenuItemCheckBox: return QAccessible::CheckBox; case ax::mojom::Role::kMenuItemRadio: return QAccessible::RadioButton; case ax::mojom::Role::kMenuListOption: return QAccessible::MenuItem; case ax::mojom::Role::kMenuListPopup: return QAccessible::PopupMenu; case ax::mojom::Role::kMeter: return QAccessible::Chart; case ax::mojom::Role::kNavigation: return QAccessible::Section; case ax::mojom::Role::kNote: return QAccessible::Note; case ax::mojom::Role::kPane: return QAccessible::Pane; case ax::mojom::Role::kParagraph: return QAccessible::Paragraph; case ax::mojom::Role::kPdfActionableHighlight: return QAccessible::Button; case ax::mojom::Role::kPdfRoot: return QAccessible::Document; case ax::mojom::Role::kPluginObject: return QAccessible::Grouping; case ax::mojom::Role::kPopUpButton: return QAccessible::ComboBox; case ax::mojom::Role::kPortal: return QAccessible::Button; case ax::mojom::Role::kPre: return QAccessible::Section; case ax::mojom::Role::kProgressIndicator: return QAccessible::ProgressBar; case ax::mojom::Role::kRadioButton: return QAccessible::RadioButton; case ax::mojom::Role::kRadioGroup: return QAccessible::Grouping; case ax::mojom::Role::kRegion: return QAccessible::Section; case ax::mojom::Role::kRow: return QAccessible::Row; case ax::mojom::Role::kRowGroup: return QAccessible::Section; case ax::mojom::Role::kRowHeader: return QAccessible::RowHeader; case ax::mojom::Role::kRuby: return QAccessible::Grouping; case ax::mojom::Role::kRubyAnnotation: return QAccessible::StaticText; case ax::mojom::Role::kScrollBar: return QAccessible::ScrollBar; case ax::mojom::Role::kScrollView: return QAccessible::Pane; case ax::mojom::Role::kSearch: return QAccessible::Section; case ax::mojom::Role::kSearchBox: return QAccessible::EditableText; case ax::mojom::Role::kSection: return QAccessible::Section; case ax::mojom::Role::kSlider: return QAccessible::Slider; case ax::mojom::Role::kSpinButton: return QAccessible::SpinBox; case ax::mojom::Role::kSplitter: return QAccessible::Splitter; case ax::mojom::Role::kStaticText: return QAccessible::StaticText; case ax::mojom::Role::kStatus: return QAccessible::Indicator; case ax::mojom::Role::kStrong: return QAccessible::StaticText; case ax::mojom::Role::kSuggestion: return QAccessible::Section; case ax::mojom::Role::kSvgRoot: return QAccessible::Graphic; case ax::mojom::Role::kSwitch: return QAccessible::Button; case ax::mojom::Role::kTable: return QAccessible::Table; case ax::mojom::Role::kTableHeaderContainer: return QAccessible::Section; case ax::mojom::Role::kTab: return QAccessible::PageTab; case ax::mojom::Role::kTabList: return QAccessible::PageTabList; case ax::mojom::Role::kTabPanel: return QAccessible::Pane; case ax::mojom::Role::kTerm: return QAccessible::StaticText; case ax::mojom::Role::kTextField: return QAccessible::EditableText; case ax::mojom::Role::kTime: case ax::mojom::Role::kTimer: return QAccessible::Clock; case ax::mojom::Role::kTitleBar: return QAccessible::Document; case ax::mojom::Role::kToggleButton: return QAccessible::Button; case ax::mojom::Role::kToolbar: return QAccessible::ToolBar; case ax::mojom::Role::kTooltip: return QAccessible::ToolTip; case ax::mojom::Role::kTree: return QAccessible::Tree; case ax::mojom::Role::kTreeGrid: return QAccessible::Tree; case ax::mojom::Role::kTreeItem: return QAccessible::TreeItem; case ax::mojom::Role::kVideo: return QAccessible::Animation; case ax::mojom::Role::kWindow: return QAccessible::Window; } return QAccessible::NoRole; } QAccessible::State BrowserAccessibilityQt::state() const { QAccessible::State state = QAccessible::State(); if (HasState(ax::mojom::State::kCollapsed)) state.collapsed = true; if (HasState(ax::mojom::State::kDefault)) state.defaultButton = true; if (HasState(ax::mojom::State::kEditable)) state.editable = true; if (HasState(ax::mojom::State::kExpanded)) state.expanded = true; if (HasState(ax::mojom::State::kFocusable)) state.focusable = true; if (HasState(ax::mojom::State::kHorizontal)) {} // FIXME if (HasState(ax::mojom::State::kHovered)) state.hotTracked = true; if (HasState(ax::mojom::State::kIgnored)) {} // FIXME if (HasState(ax::mojom::State::kInvisible)) state.invisible = true; if (HasState(ax::mojom::State::kLinked)) state.linked = true; if (HasState(ax::mojom::State::kMultiline)) state.multiLine = true; if (HasState(ax::mojom::State::kMultiselectable)) state.multiSelectable = true; if (HasState(ax::mojom::State::kProtected)) state.passwordEdit = true; if (HasState(ax::mojom::State::kRequired)) {} // FIXME if (HasState(ax::mojom::State::kRichlyEditable)) {} // FIXME if (HasState(ax::mojom::State::kVertical)) {} // FIXME if (HasState(ax::mojom::State::kVisited)) state.traversed = true; if (IsOffscreen()) state.offscreen = true; if (manager()->GetFocus() == this) state.focused = true; if (GetBoolAttribute(ax::mojom::BoolAttribute::kBusy)) state.busy = true; if (GetBoolAttribute(ax::mojom::BoolAttribute::kModal)) state.modal = true; if (HasBoolAttribute(ax::mojom::BoolAttribute::kSelected)) { state.selectable = true; state.selected = GetBoolAttribute(ax::mojom::BoolAttribute::kSelected); } if (HasIntAttribute(ax::mojom::IntAttribute::kCheckedState)) { state.checkable = true; const ax::mojom::CheckedState checkedState = static_cast(GetIntAttribute(ax::mojom::IntAttribute::kCheckedState)); switch (checkedState) { case ax::mojom::CheckedState::kTrue: if (GetRole() == ax::mojom::Role::kToggleButton) state.pressed = true; else state.checked = true; break; case ax::mojom::CheckedState::kMixed: state.checkStateMixed = true; break; case ax::mojom::CheckedState::kFalse: case ax::mojom::CheckedState::kNone: break; } } if (HasIntAttribute(ax::mojom::IntAttribute::kRestriction)) { const ax::mojom::Restriction restriction = static_cast(GetIntAttribute(ax::mojom::IntAttribute::kRestriction)); switch (restriction) { case ax::mojom::Restriction::kReadOnly: state.readOnly = true; break; case ax::mojom::Restriction::kDisabled: state.disabled = true; break; case ax::mojom::Restriction::kNone: break; } } if (HasIntAttribute(ax::mojom::IntAttribute::kHasPopup)) { const ax::mojom::HasPopup hasPopup = static_cast(GetIntAttribute(ax::mojom::IntAttribute::kHasPopup)); switch (hasPopup) { case ax::mojom::HasPopup::kFalse: break; case ax::mojom::HasPopup::kTrue: case ax::mojom::HasPopup::kMenu: case ax::mojom::HasPopup::kListbox: case ax::mojom::HasPopup::kTree: case ax::mojom::HasPopup::kGrid: case ax::mojom::HasPopup::kDialog: state.hasPopup = true; break; } } return state; } void BrowserAccessibilityQt::Destroy() { // delete this QAccessible::Id interfaceId = QAccessible::uniqueId(this); QAccessible::deleteAccessibleInterface(interfaceId); } QStringList BrowserAccessibilityQt::actionNames() const { QStringList actions; if (HasState(ax::mojom::State::kFocusable)) actions << QAccessibleActionInterface::setFocusAction(); return actions; } void BrowserAccessibilityQt::doAction(const QString &actionName) { if (actionName == QAccessibleActionInterface::setFocusAction()) manager()->SetFocus(*this); } QStringList BrowserAccessibilityQt::keyBindingsForAction(const QString &actionName) const { QT_NOT_YET_IMPLEMENTED return QStringList(); } void BrowserAccessibilityQt::addSelection(int startOffset, int endOffset) { manager()->SetSelection(AXRange(CreatePositionAt(startOffset), CreatePositionAt(endOffset))); } QString BrowserAccessibilityQt::attributes(int offset, int *startOffset, int *endOffset) const { *startOffset = offset; *endOffset = offset; return QString(); } int BrowserAccessibilityQt::cursorPosition() const { int pos = 0; GetIntAttribute(ax::mojom::IntAttribute::kTextSelStart, &pos); return pos; } QRect BrowserAccessibilityQt::characterRect(int /*offset*/) const { QT_NOT_YET_IMPLEMENTED return QRect(); } int BrowserAccessibilityQt::selectionCount() const { int start = 0; int end = 0; GetIntAttribute(ax::mojom::IntAttribute::kTextSelStart, &start); GetIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, &end); if (start != end) return 1; return 0; } int BrowserAccessibilityQt::offsetAtPoint(const QPoint &/*point*/) const { QT_NOT_YET_IMPLEMENTED return 0; } void BrowserAccessibilityQt::selection(int selectionIndex, int *startOffset, int *endOffset) const { Q_ASSERT(startOffset && endOffset); *startOffset = 0; *endOffset = 0; if (selectionIndex != 0) return; GetIntAttribute(ax::mojom::IntAttribute::kTextSelStart, startOffset); GetIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, endOffset); } QString BrowserAccessibilityQt::text(int startOffset, int endOffset) const { return text(QAccessible::Value).mid(startOffset, endOffset - startOffset); } void BrowserAccessibilityQt::removeSelection(int selectionIndex) { manager()->SetSelection(AXRange(CreatePositionAt(0), CreatePositionAt(0))); } void BrowserAccessibilityQt::setCursorPosition(int position) { manager()->SetSelection(AXRange(CreatePositionAt(position), CreatePositionAt(position))); } void BrowserAccessibilityQt::setSelection(int selectionIndex, int startOffset, int endOffset) { if (selectionIndex != 0) return; manager()->SetSelection(AXRange(CreatePositionAt(startOffset), CreatePositionAt(endOffset))); } int BrowserAccessibilityQt::characterCount() const { return text(QAccessible::Value).length(); } void BrowserAccessibilityQt::scrollToSubstring(int startIndex, int endIndex) { int count = characterCount(); if (startIndex < endIndex && endIndex < count) manager()->ScrollToMakeVisible(*this, GetRootFrameHypertextRangeBoundsRect( startIndex, endIndex - startIndex, ui::AXClippingBehavior::kUnclipped)); } QVariant BrowserAccessibilityQt::currentValue() const { QVariant result; float value; if (GetFloatAttribute(ax::mojom::FloatAttribute::kValueForRange, &value)) { result = (double) value; } return result; } void BrowserAccessibilityQt::setCurrentValue(const QVariant &value) { // not yet implemented anywhere in blink QT_NOT_YET_IMPLEMENTED } QVariant BrowserAccessibilityQt::maximumValue() const { QVariant result; float value; if (GetFloatAttribute(ax::mojom::FloatAttribute::kMaxValueForRange, &value)) { result = (double) value; } return result; } QVariant BrowserAccessibilityQt::minimumValue() const { QVariant result; float value; if (GetFloatAttribute(ax::mojom::FloatAttribute::kMinValueForRange, &value)) { result = (double) value; } return result; } QVariant BrowserAccessibilityQt::minimumStepSize() const { QVariant result; float value; if (GetFloatAttribute(ax::mojom::FloatAttribute::kStepValueForRange, &value)) { result = (double) value; } return result; } QAccessibleInterface *BrowserAccessibilityQt::cellAt(int row, int column) const { int columns = 0; int rows = 0; if (!GetIntAttribute(ax::mojom::IntAttribute::kTableColumnCount, &columns) || !GetIntAttribute(ax::mojom::IntAttribute::kTableRowCount, &rows) || columns <= 0 || rows <= 0) { return 0; } if (row < 0 || row >= rows || column < 0 || column >= columns) return 0; base::Optional cell_id = GetCellId(row, column); BrowserAccessibility* cell = cell_id ? manager()->GetFromID(*cell_id) : nullptr; if (cell) { QAccessibleInterface *iface = static_cast(cell); return iface; } return nullptr; } QAccessibleInterface *BrowserAccessibilityQt::caption() const { return nullptr; } QAccessibleInterface *BrowserAccessibilityQt::summary() const { return nullptr; } QString BrowserAccessibilityQt::columnDescription(int column) const { return QString(); } QString BrowserAccessibilityQt::rowDescription(int row) const { return QString(); } int BrowserAccessibilityQt::columnCount() const { int columns = 0; if (GetIntAttribute(ax::mojom::IntAttribute::kTableColumnCount, &columns)) return columns; return 0; } int BrowserAccessibilityQt::rowCount() const { int rows = 0; if (GetIntAttribute(ax::mojom::IntAttribute::kTableRowCount, &rows)) return rows; return 0; } int BrowserAccessibilityQt::selectedCellCount() const { return 0; } int BrowserAccessibilityQt::selectedColumnCount() const { return 0; } int BrowserAccessibilityQt::selectedRowCount() const { return 0; } QList BrowserAccessibilityQt::selectedCells() const { return QList(); } QList BrowserAccessibilityQt::selectedColumns() const { return QList(); } QList BrowserAccessibilityQt::selectedRows() const { return QList(); } bool BrowserAccessibilityQt::isColumnSelected(int /*column*/) const { return false; } bool BrowserAccessibilityQt::isRowSelected(int /*row*/) const { return false; } bool BrowserAccessibilityQt::selectRow(int /*row*/) { return false; } bool BrowserAccessibilityQt::selectColumn(int /*column*/) { return false; } bool BrowserAccessibilityQt::unselectRow(int /*row*/) { return false; } bool BrowserAccessibilityQt::unselectColumn(int /*column*/) { return false; } int BrowserAccessibilityQt::columnExtent() const { return 1; } QList BrowserAccessibilityQt::columnHeaderCells() const { return QList(); } int BrowserAccessibilityQt::columnIndex() const { int column = 0; if (GetIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex, &column)) return column; return 0; } int BrowserAccessibilityQt::rowExtent() const { return 1; } QList BrowserAccessibilityQt::rowHeaderCells() const { return QList(); } int BrowserAccessibilityQt::rowIndex() const { int row = 0; if (GetIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex, &row)) return row; return 0; } bool BrowserAccessibilityQt::isSelected() const { return false; } QAccessibleInterface *BrowserAccessibilityQt::table() const { BrowserAccessibility* find_table = PlatformGetParent(); while (find_table && find_table->GetRole() != ax::mojom::Role::kTable) find_table = find_table->PlatformGetParent(); if (!find_table) return nullptr; return static_cast(find_table); } void BrowserAccessibilityQt::modelChange(QAccessibleTableModelChangeEvent *) { } } // namespace content #endif // QT_CONFIG(accessibility)