#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "ui/accessibility/platform/browser_accessibility_com_win.h"
#include <algorithm>
#include <iterator>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/typed_macros.h"
#include "base/win/enum_variant.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#include "ui/accessibility/platform/browser_accessibility_manager_win.h"
#include "ui/accessibility/platform/browser_accessibility_win.h"
#include "ui/accessibility/ax_common.h"
#include "ui/accessibility/ax_enum_localization_util.h"
#include "ui/accessibility/ax_enum_util.h"
#include "ui/accessibility/ax_mode.h"
#include "ui/accessibility/ax_role_properties.h"
#include "ui/accessibility/platform/ax_platform.h"
#include "ui/base/win/accessibility_ids_win.h"
#include "ui/base/win/atl_module.h"
namespace ui {
BrowserAccessibilityComWin::WinAttributes::WinAttributes() = default;
BrowserAccessibilityComWin::WinAttributes::~WinAttributes() = default;
BrowserAccessibilityComWin::UpdateState::UpdateState() = default;
BrowserAccessibilityComWin::UpdateState::~UpdateState() = default;
BrowserAccessibilityComWin::BrowserAccessibilityComWin()
: win_attributes_(new WinAttributes()),
previous_scroll_x_(0),
previous_scroll_y_(0) {}
BrowserAccessibilityComWin::~BrowserAccessibilityComWin() = default;
void BrowserAccessibilityComWin::OnReferenced() {
TRACE_EVENT_INSTANT("accessibility", "OnReferenced",
perfetto::Flow::FromPointer(this));
}
void BrowserAccessibilityComWin::OnDereferenced() {
TRACE_EVENT_INSTANT("accessibility", "OnDereferenced",
perfetto::Flow::FromPointer(this));
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_attributes(BSTR* attributes) {
return AXPlatformNodeWin::get_attributes(attributes);
}
IFACEMETHODIMP BrowserAccessibilityComWin::scrollTo(IA2ScrollType scroll_type) {
return AXPlatformNodeWin::scrollTo(scroll_type);
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_appName(BSTR* app_name) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_appName");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_APP_NAME);
if (!app_name)
return E_INVALIDARG;
*app_name = SysAllocString(
base::UTF8ToWide(AXPlatform::GetInstance().GetProductName()).c_str());
DCHECK(*app_name);
return *app_name ? S_OK : E_FAIL;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_appVersion(BSTR* app_version) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_appVersion");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_APP_VERSION);
if (!app_version)
return E_INVALIDARG;
*app_version = SysAllocString(
base::UTF8ToWide(AXPlatform::GetInstance().GetProductVersion()).c_str());
DCHECK(*app_version);
return *app_version ? S_OK : E_FAIL;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_toolkitName(BSTR* toolkit_name) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_toolkitName");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TOOLKIT_NAME);
if (!toolkit_name)
return E_INVALIDARG;
*toolkit_name = SysAllocString(FRAMEWORK_ID);
DCHECK(*toolkit_name);
return *toolkit_name ? S_OK : E_FAIL;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_toolkitVersion(
BSTR* toolkit_version) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_toolkitVersion");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TOOLKIT_VERSION);
if (!toolkit_version)
return E_INVALIDARG;
*toolkit_version = SysAllocString(
base::UTF8ToWide(AXPlatform::GetInstance().GetToolkitVersion()).c_str());
DCHECK(*toolkit_version);
return *toolkit_version ? S_OK : E_FAIL;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_description(BSTR* desc) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_description");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_DESCRIPTION);
if (IsDestroyed()) {
return E_FAIL;
}
if (!desc)
return E_INVALIDARG;
if (description().empty())
return S_FALSE;
*desc = SysAllocString(description().c_str());
DCHECK(*desc);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_imagePosition(
IA2CoordinateType coordinate_type,
LONG* x,
LONG* y) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_imagePosition");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_IMAGE_POSITION);
if (IsDestroyed()) {
return E_FAIL;
}
if (!x || !y)
return E_INVALIDARG;
BrowserAccessibilityWin* const owner = GetOwner();
if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
gfx::Rect bounds = owner->GetUnclippedScreenBoundsRect();
*x = bounds.x();
*y = bounds.y();
} else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
gfx::Rect bounds = owner->GetClippedRootFrameBoundsRect();
gfx::Rect parent_bounds;
if (BrowserAccessibility* parent = owner->PlatformGetParent(); parent) {
parent_bounds = parent->GetClippedRootFrameBoundsRect();
}
*x = bounds.x() - parent_bounds.x();
*y = bounds.y() - parent_bounds.y();
} else {
return E_INVALIDARG;
}
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_imageSize(LONG* height,
LONG* width) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_imageSize");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_IMAGE_SIZE);
if (IsDestroyed()) {
return E_FAIL;
}
if (!height || !width)
return E_INVALIDARG;
gfx::Rect image_rect = GetOwner()->GetClippedRootFrameBoundsRect();
*height = image_rect.height();
*width = image_rect.width();
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_characterExtents(
LONG offset,
IA2CoordinateType coordinate_type,
LONG* out_x,
LONG* out_y,
LONG* out_width,
LONG* out_height) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_characterExtents");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_CHARACTER_EXTENTS);
if (IsDestroyed()) {
return E_FAIL;
}
if (!out_x || !out_y || !out_width || !out_height) {
return E_INVALIDARG;
}
OnInlineTextBoxesUsed();
const std::u16string& text_str = GetHypertext();
HandleSpecialTextOffset(&offset);
if (offset < 0 || offset > static_cast<LONG>(text_str.size()))
return E_INVALIDARG;
BrowserAccessibilityWin* const owner = GetOwner();
gfx::Rect character_bounds;
if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
character_bounds = owner->GetScreenHypertextRangeBoundsRect(
offset, 1, AXClippingBehavior::kUnclipped);
} else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
character_bounds = owner->GetRootFrameHypertextRangeBoundsRect(
offset, 1, AXClippingBehavior::kUnclipped);
if (BrowserAccessibility* parent = owner->PlatformGetParent(); parent) {
character_bounds -=
parent->GetUnclippedRootFrameBoundsRect().OffsetFromOrigin();
}
} else {
return E_INVALIDARG;
}
*out_x = character_bounds.x();
*out_y = character_bounds.y();
*out_width = character_bounds.width();
*out_height = character_bounds.height();
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_nSelections(LONG* n_selections) {
return AXPlatformNodeWin::get_nSelections(n_selections);
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_selection(LONG selection_index,
LONG* start_offset,
LONG* end_offset) {
return AXPlatformNodeWin::get_selection(selection_index, start_offset,
end_offset);
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_text(LONG start_offset,
LONG end_offset,
BSTR* text) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_text");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TEXT);
if (IsDestroyed()) {
return E_FAIL;
}
if (!text) {
return E_INVALIDARG;
}
OnExtendedPropertiesUsed();
const std::u16string& text_str = GetHypertext();
HandleSpecialTextOffset(&start_offset);
HandleSpecialTextOffset(&end_offset);
if (start_offset > end_offset)
std::swap(start_offset, end_offset);
LONG len = static_cast<LONG>(text_str.length());
if (start_offset < 0 || start_offset > len)
return E_INVALIDARG;
if (end_offset < 0 || end_offset > len)
return E_INVALIDARG;
std::u16string substr =
text_str.substr(start_offset, end_offset - start_offset);
if (substr.empty())
return S_FALSE;
*text = SysAllocString(base::as_wcstr(substr));
DCHECK(*text);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_newText(
IA2TextSegment* new_text) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_newText");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_NEW_TEXT);
if (IsDestroyed()) {
return E_FAIL;
}
if (!new_text)
return E_INVALIDARG;
if (!update_state_) {
return E_FAIL;
}
OnExtendedPropertiesUsed();
size_t start, old_len, new_len;
ComputeHypertextRemovedAndInserted(update_state_->old_hypertext, &start,
&old_len, &new_len);
if (new_len == 0)
return E_FAIL;
std::u16string substr = GetHypertext().substr(start, new_len);
new_text->text = SysAllocString(base::as_wcstr(substr));
new_text->start = static_cast<LONG>(start);
new_text->end = static_cast<LONG>(start + new_len);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_oldText(
IA2TextSegment* old_text) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_oldText");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_OLD_TEXT);
if (IsDestroyed()) {
return E_FAIL;
}
if (!old_text)
return E_INVALIDARG;
if (!update_state_) {
return E_FAIL;
}
OnExtendedPropertiesUsed();
size_t start, old_len, new_len;
ComputeHypertextRemovedAndInserted(update_state_->old_hypertext, &start,
&old_len, &new_len);
if (old_len == 0)
return E_FAIL;
const std::u16string& old_hypertext = update_state_->old_hypertext.hypertext;
std::u16string substr = old_hypertext.substr(start, old_len);
old_text->text = SysAllocString(base::as_wcstr(substr));
old_text->start = static_cast<LONG>(start);
old_text->end = static_cast<LONG>(start + old_len);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::scrollSubstringTo(
LONG start_index,
LONG end_index,
IA2ScrollType scroll_type) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("scrollSubstringTo");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SCROLL_SUBSTRING_TO);
if (IsDestroyed()) {
return E_FAIL;
}
OnInlineTextBoxesUsed();
return scrollTo(scroll_type);
}
IFACEMETHODIMP BrowserAccessibilityComWin::scrollSubstringToPoint(
LONG start_index,
LONG end_index,
IA2CoordinateType coordinate_type,
LONG x,
LONG y) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("scrollSubstringToPoint");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SCROLL_SUBSTRING_TO_POINT);
if (IsDestroyed()) {
return E_FAIL;
}
OnInlineTextBoxesUsed();
if (start_index > end_index)
std::swap(start_index, end_index);
LONG length = end_index - start_index + 1;
DCHECK_GE(length, 0);
BrowserAccessibilityWin* const owner = GetOwner();
gfx::Rect string_bounds = owner->GetRootFrameHypertextRangeBoundsRect(
start_index, length, AXClippingBehavior::kUnclipped);
string_bounds -= owner->GetUnclippedRootFrameBoundsRect().OffsetFromOrigin();
x -= string_bounds.x();
y -= string_bounds.y();
return scrollToPoint(coordinate_type, x, y);
}
IFACEMETHODIMP BrowserAccessibilityComWin::setCaretOffset(LONG offset) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("setCaretOffset");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SET_CARET_OFFSET);
if (IsDestroyed()) {
return E_FAIL;
}
OnExtendedPropertiesUsed();
SetIA2HypertextSelection(offset, offset);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::setSelection(LONG selection_index,
LONG start_offset,
LONG end_offset) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("setSelection");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SET_SELECTION);
if (IsDestroyed()) {
return E_FAIL;
}
if (selection_index != 0)
return E_INVALIDARG;
OnExtendedPropertiesUsed();
SetIA2HypertextSelection(start_offset, end_offset);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_attributes(
LONG offset,
LONG* start_offset,
LONG* end_offset,
BSTR* text_attributes) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_attributes");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_IATEXT_GET_ATTRIBUTES);
if (IsDestroyed()) {
return E_FAIL;
}
if (!start_offset || !end_offset || !text_attributes)
return E_INVALIDARG;
OnExtendedPropertiesUsed();
*start_offset = *end_offset = 0;
*text_attributes = nullptr;
const std::u16string text = GetHypertext();
HandleSpecialTextOffset(&offset);
if (offset < 0 || offset > static_cast<LONG>(text.size()))
return E_INVALIDARG;
ComputeStylesIfNeeded();
*start_offset = FindStartOfStyle(offset, ax::mojom::MoveDirection::kBackward);
*end_offset = FindStartOfStyle(offset, ax::mojom::MoveDirection::kForward);
std::ostringstream attributes_stream;
auto iter = offset_to_text_attributes().find(*start_offset);
if (iter != offset_to_text_attributes().end()) {
const TextAttributeList& attributes = iter->second;
for (const TextAttribute& attribute : attributes) {
if (attribute.first == "language" && attribute.second == "en-US")
continue;
attributes_stream << attribute.first << ":" << attribute.second << ";";
}
}
std::wstring attributes_str = base::UTF8ToWide(attributes_stream.str());
*text_attributes = SysAllocString(attributes_str.c_str());
DCHECK(*text_attributes);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_nHyperlinks(
LONG* hyperlink_count) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_nHyperlinks");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_N_HYPERLINKS);
if (IsDestroyed()) {
return E_FAIL;
}
if (!hyperlink_count)
return E_INVALIDARG;
OnExtendedPropertiesUsed();
*hyperlink_count = hypertext_.hyperlink_offset_to_index.size();
DCHECK(!IsIframe(GetOwner()->GetRole()) || *hyperlink_count <= 1)
<< "iframes should have 1 hyperlink, unless the child document is "
"destroyed/unloaded, in which case it should have 0";
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_hyperlink(
LONG index,
IAccessibleHyperlink** hyperlink) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_hyperlink");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_HYPERLINK);
if (IsDestroyed()) {
return E_FAIL;
}
if (!hyperlink || index < 0 ||
index >= static_cast<LONG>(hypertext_.hyperlinks.size())) {
return E_INVALIDARG;
}
OnExtendedPropertiesUsed();
*hyperlink = nullptr;
DCHECK(!IsIframe(GetOwner()->GetRole()) || index == 0)
<< "An iframe cannot have more than 1 hyperlink";
int32_t id = hypertext_.hyperlinks[index];
AXPlatformNode* node = AXPlatformNodeWin::GetFromUniqueId(id);
if (!node) {
AXTreeManager* manager = GetDelegate()->GetTreeManager();
LOG(FATAL) << "Hyperlink error:\n index=" << index
<< " nHyperLinks=" << hypertext_.hyperlinks.size()
<< " hyperlink_id=" << id << "\nparent=" << GetDelegate()->node()
<< "\nframe=" << manager->GetRoot()
<< "\nroot=" << manager->GetRootManager()->GetRoot();
return E_FAIL;
}
auto* link = static_cast<BrowserAccessibilityComWin*>(node);
if (!link)
return E_FAIL;
*hyperlink = static_cast<IAccessibleHyperlink*>(link->NewReference());
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_hyperlinkIndex(
LONG char_index,
LONG* hyperlink_index) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_hyperlinkIndex");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_HYPERLINK_INDEX);
if (IsDestroyed()) {
return E_FAIL;
}
if (!hyperlink_index)
return E_INVALIDARG;
if (char_index < 0 ||
char_index >= static_cast<LONG>(GetHypertext().size())) {
return E_INVALIDARG;
}
OnExtendedPropertiesUsed();
auto it = hypertext_.hyperlink_offset_to_index.find(char_index);
if (it == hypertext_.hyperlink_offset_to_index.end()) {
*hyperlink_index = -1;
return S_FALSE;
}
*hyperlink_index = it->second;
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_anchor(LONG index,
VARIANT* anchor) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_anchor");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_ANCHOR);
if (IsDestroyed() || !IsHyperlink()) {
return E_FAIL;
}
if (index != 0 || !anchor)
return E_INVALIDARG;
OnExtendedPropertiesUsed();
BSTR ia2_hypertext = SysAllocString(base::as_wcstr(GetHypertext()));
DCHECK(ia2_hypertext);
anchor->vt = VT_BSTR;
anchor->bstrVal = ia2_hypertext;
if (!SysStringLen(ia2_hypertext))
return S_FALSE;
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_anchorTarget(
LONG index,
VARIANT* anchor_target) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_anchorTarget");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_ANCHOR_TARGET);
if (IsDestroyed() || !IsHyperlink()) {
return E_FAIL;
}
if (index != 0 || !anchor_target)
return E_INVALIDARG;
OnExtendedPropertiesUsed();
BSTR target;
if (!(MSAAState() & STATE_SYSTEM_LINKED) ||
FAILED(GetStringAttributeAsBstr(ax::mojom::StringAttribute::kUrl,
&target))) {
target = SysAllocString(L"");
}
DCHECK(target);
anchor_target->vt = VT_BSTR;
anchor_target->bstrVal = target;
if (!SysStringLen(target))
return S_FALSE;
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_startIndex(LONG* index) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_startIndex");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_START_INDEX);
if (IsDestroyed() || !IsHyperlink()) {
return E_FAIL;
}
if (!index)
return E_INVALIDARG;
OnExtendedPropertiesUsed();
int32_t hypertext_offset = 0;
auto* parent = GetOwner()->PlatformGetParent();
if (parent) {
hypertext_offset =
ToBrowserAccessibilityComWin(parent)->GetHypertextOffsetFromChild(this);
}
*index = static_cast<LONG>(hypertext_offset);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_endIndex(LONG* index) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_endIndex");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_END_INDEX);
if (IsDestroyed()) {
return E_FAIL;
}
OnExtendedPropertiesUsed();
LONG start_index;
HRESULT hr = get_startIndex(&start_index);
if (hr == S_OK)
*index = start_index + 1;
return hr;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_valid(boolean* valid) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_valid");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_VALID);
return E_NOTIMPL;
}
IFACEMETHODIMP BrowserAccessibilityComWin::nActions(LONG* n_actions) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("nActions");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_N_ACTIONS);
if (IsDestroyed()) {
return E_FAIL;
}
if (!n_actions)
return E_INVALIDARG;
OnExtendedPropertiesUsed();
BrowserAccessibilityWin* const owner = GetOwner();
*n_actions = static_cast<LONG>(
owner->GetSupportedActions().size() +
owner->GetIntListAttribute(ax::mojom::IntListAttribute::kActionsIds)
.size());
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::doAction(LONG action_index) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("doAction");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_DO_ACTION);
if (IsDestroyed()) {
return E_FAIL;
}
OnExtendedPropertiesUsed();
BrowserAccessibilityWin* const owner = GetOwner();
const std::vector<ax::mojom::Action> actions = owner->GetSupportedActions();
const std::vector<int32_t>& aria_actions =
owner->GetIntListAttribute(ax::mojom::IntListAttribute::kActionsIds);
if (action_index < 0 ||
action_index >= static_cast<LONG>(actions.size() + aria_actions.size())) {
return E_INVALIDARG;
}
AXActionData data;
if (action_index < static_cast<LONG>(actions.size())) {
data.action = actions[action_index];
owner->AccessibilityPerformAction(data);
return S_OK;
}
int32_t aria_action_id = aria_actions[action_index - actions.size()];
data.action = ax::mojom::Action::kDoDefault;
GetFromID(aria_action_id)->GetOwner()->AccessibilityPerformAction(data);
return S_OK;
}
IFACEMETHODIMP
BrowserAccessibilityComWin::get_description(LONG action_index,
BSTR* description) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_description");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_IAACTION_GET_DESCRIPTION);
if (IsDestroyed()) {
return E_FAIL;
}
OnExtendedPropertiesUsed();
return E_NOTIMPL;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_keyBinding(LONG action_index,
LONG n_max_bindings,
BSTR** key_bindings,
LONG* n_bindings) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_keyBinding");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_KEY_BINDING);
if (IsDestroyed()) {
return E_FAIL;
}
if (!key_bindings || !n_bindings) {
return E_INVALIDARG;
}
OnExtendedPropertiesUsed();
*key_bindings = nullptr;
*n_bindings = 0;
BrowserAccessibilityWin* const owner = GetOwner();
const std::vector<ax::mojom::Action> actions = owner->GetSupportedActions();
if (action_index < 0 || action_index >= static_cast<LONG>(actions.size())) {
return E_INVALIDARG;
}
std::u16string key_binding_string;
if (action_index != 0 || !owner->HasDefaultActionVerb() ||
!owner->GetString16Attribute(ax::mojom::StringAttribute::kAccessKey,
&key_binding_string)) {
return S_FALSE;
}
*n_bindings = 1;
*key_bindings = static_cast<BSTR*>(CoTaskMemAlloc(sizeof(BSTR)));
(*key_bindings)[0] = SysAllocString(base::as_wcstr(key_binding_string));
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_name(LONG action_index,
BSTR* name) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_name");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_NAME);
if (IsDestroyed()) {
return E_FAIL;
}
if (!name) {
return E_INVALIDARG;
}
OnExtendedPropertiesUsed();
BrowserAccessibilityWin* const owner = GetOwner();
const std::vector<ax::mojom::Action> actions = owner->GetSupportedActions();
const std::vector<int32_t>& aria_actions =
owner->GetIntListAttribute(ax::mojom::IntListAttribute::kActionsIds);
if (action_index < 0 ||
action_index >= static_cast<LONG>(actions.size() + aria_actions.size())) {
*name = nullptr;
return E_INVALIDARG;
}
int action;
std::string action_verb;
if (action_index == 0 &&
owner->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb,
&action)) {
action_verb =
ui::ToString(static_cast<ax::mojom::DefaultActionVerb>(action));
} else if (action_index < static_cast<LONG>(actions.size())) {
action_verb = ui::ToString(actions[action_index]);
} else {
int32_t aria_action_id = aria_actions[action_index - actions.size()];
BrowserAccessibilityComWin* aria_action_obj = GetFromID(aria_action_id);
const std::string& html_id = aria_action_obj->GetStringAttribute(
ax::mojom::StringAttribute::kHtmlId);
action_verb = html_id.empty()
? AXPlatformNodeBase::kAriaActionsPrefix
: AXPlatformNodeBase::kAriaActionsPrefix + "_" + html_id;
}
if (action_verb.empty() || action_verb.compare("none") == 0) {
*name = nullptr;
return S_FALSE;
}
*name = SysAllocString(base::as_wcstr(base::UTF8ToUTF16(action_verb)));
DCHECK(name);
return S_OK;
}
IFACEMETHODIMP
BrowserAccessibilityComWin::get_localizedName(LONG action_index,
BSTR* localized_name) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_localizedName");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_LOCALIZED_NAME);
if (IsDestroyed()) {
return E_FAIL;
}
if (!localized_name) {
return E_INVALIDARG;
}
OnExtendedPropertiesUsed();
BrowserAccessibilityWin* const owner = GetOwner();
const std::vector<ax::mojom::Action> actions = owner->GetSupportedActions();
const std::vector<int32_t>& aria_actions =
owner->GetIntListAttribute(ax::mojom::IntListAttribute::kActionsIds);
if (action_index < 0 ||
action_index >= static_cast<LONG>(actions.size() + aria_actions.size())) {
*localized_name = nullptr;
return E_INVALIDARG;
}
int action;
std::string action_verb;
if (action_index < static_cast<LONG>(actions.size())) {
if (!owner->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb,
&action) ||
action_index != 0) {
return get_name(action_index, localized_name);
}
action_verb =
ToLocalizedString(static_cast<ax::mojom::DefaultActionVerb>(action));
} else {
int32_t aria_action_id = aria_actions[action_index - actions.size()];
BrowserAccessibilityComWin* aria_action_obj = GetFromID(aria_action_id);
action_verb = aria_action_obj->GetName();
}
if (action_verb.empty()) {
*localized_name = nullptr;
return S_FALSE;
}
*localized_name =
SysAllocString(base::as_wcstr(base::UTF8ToUTF16(action_verb)));
DCHECK(localized_name);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_URL(BSTR* url) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_URL");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_URL);
if (IsDestroyed()) {
return E_FAIL;
}
auto* manager = Manager();
if (!manager)
return E_FAIL;
if (!url)
return E_INVALIDARG;
if (GetOwner() != manager->GetBrowserAccessibilityRoot()) {
return E_FAIL;
}
OnExtendedPropertiesUsed();
std::string str = manager->GetTreeData().url;
if (str.empty())
return S_FALSE;
*url = SysAllocString(base::UTF8ToWide(str).c_str());
DCHECK(*url);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_title(BSTR* title) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_title");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TITLE);
if (IsDestroyed()) {
return E_FAIL;
}
auto* manager = Manager();
if (!manager)
return E_FAIL;
if (!title)
return E_INVALIDARG;
OnExtendedPropertiesUsed();
std::string str = manager->GetTreeData().title;
if (str.empty())
return S_FALSE;
*title = SysAllocString(base::UTF8ToWide(str).c_str());
DCHECK(*title);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_mimeType(BSTR* mime_type) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_mimeType");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_MIME_TYPE);
if (IsDestroyed()) {
return E_FAIL;
}
auto* manager = Manager();
if (!manager)
return E_FAIL;
if (!mime_type)
return E_INVALIDARG;
OnExtendedPropertiesUsed();
std::string str = manager->GetTreeData().mimetype;
if (str.empty())
return S_FALSE;
*mime_type = SysAllocString(base::UTF8ToWide(str).c_str());
DCHECK(*mime_type);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_docType(BSTR* doc_type) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_docType");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_DOC_TYPE);
if (IsDestroyed()) {
return E_FAIL;
}
auto* manager = Manager();
if (!manager)
return E_FAIL;
if (!doc_type)
return E_INVALIDARG;
OnExtendedPropertiesUsed();
std::string str = manager->GetTreeData().doctype;
if (str.empty())
return S_FALSE;
*doc_type = SysAllocString(base::UTF8ToWide(str).c_str());
DCHECK(*doc_type);
return S_OK;
}
IFACEMETHODIMP
BrowserAccessibilityComWin::get_nameSpaceURIForID(SHORT name_space_id,
BSTR* name_space_uri) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_nameSpaceURIForID");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_NAMESPACE_URI_FOR_ID);
if (IsDestroyed()) {
return E_FAIL;
}
OnExtendedPropertiesUsed();
return E_NOTIMPL;
}
IFACEMETHODIMP
BrowserAccessibilityComWin::put_alternateViewMediaTypes(
BSTR* comma_separated_media_types) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("put_alternateViewMediaTypes");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_PUT_ALTERNATE_VIEW_MEDIA_TYPES);
if (IsDestroyed()) {
return E_FAIL;
}
OnExtendedPropertiesUsed();
return E_NOTIMPL;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_nodeInfo(
BSTR* node_name,
SHORT* name_space_id,
BSTR* node_value,
unsigned int* num_children,
unsigned int* unique_id,
USHORT* node_type) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_nodeInfo");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_NODE_INFO);
if (IsDestroyed()) {
return E_FAIL;
}
if (!node_name || !name_space_id || !node_value || !num_children ||
!unique_id || !node_type) {
return E_INVALIDARG;
}
OnExtendedPropertiesUsed();
BrowserAccessibilityWin* const owner = GetOwner();
std::u16string tag;
if (owner->GetString16Attribute(ax::mojom::StringAttribute::kHtmlTag, &tag)) {
*node_name = SysAllocString(base::as_wcstr(tag));
} else {
*node_name = nullptr;
}
*name_space_id = 0;
*node_value = SysAllocString(value().c_str());
*num_children = owner->PlatformChildCount();
*unique_id = -AXPlatformNodeWin::GetUniqueId();
if (ui::IsPlatformDocument(owner->GetRole())) {
*node_type = NODETYPE_DOCUMENT;
} else if (owner->IsText()) {
*node_type = NODETYPE_TEXT;
} else {
*node_type = NODETYPE_ELEMENT;
}
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_attributes(USHORT max_attribs,
BSTR* attrib_names,
SHORT* name_space_id,
BSTR* attrib_values,
USHORT* num_attribs) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_attributes");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_ISIMPLEDOMNODE_GET_ATTRIBUTES);
if (IsDestroyed()) {
return E_FAIL;
}
if (!IsWebContent()) {
return E_FAIL;
}
if (!attrib_names || !name_space_id || !attrib_values || !num_attribs)
return E_INVALIDARG;
AXPlatform::GetInstance().OnHTMLAttributesUsed();
#define ADD_ATTRIBUTE(name, value) \
if (index < max_attribs) { \
attrib_names[index] = SysAllocString(base::UTF8ToWide(name).c_str()); \
attrib_values[index] = SysAllocString(base::UTF8ToWide(value).c_str()); \
++index; \
}
BrowserAccessibilityWin* const owner = GetOwner();
USHORT index = 0;
if (int max_length =
owner->GetIntAttribute(ax::mojom::IntAttribute::kMaxLength)) {
ADD_ATTRIBUTE("maxlength", base::NumberToString(max_length));
}
if (owner->GetData().GetNameFrom() == ax::mojom::NameFrom::kAttribute &&
!ui::IsImage(owner->GetRole())) {
ADD_ATTRIBUTE("aria-label",
owner->GetStringAttribute(ax::mojom::StringAttribute::kName));
}
const std::string& type_attr =
owner->GetStringAttribute(ax::mojom::StringAttribute::kInputType);
if (!type_attr.empty()) {
ADD_ATTRIBUTE("type", type_attr);
}
const std::string& value_attr =
owner->GetStringAttribute(ax::mojom::StringAttribute::kValue);
if (!value_attr.empty()) {
ADD_ATTRIBUTE("value", value_attr);
}
const std::string& name_attr =
owner->GetStringAttribute(ax::mojom::StringAttribute::kHtmlInputName);
if (!name_attr.empty()) {
ADD_ATTRIBUTE("name", name_attr);
}
if (ui::IsLink(owner->GetRole())) {
ADD_ATTRIBUTE("href",
owner->GetStringAttribute(ax::mojom::StringAttribute::kUrl));
}
const std::string& id_attr =
owner->GetStringAttribute(ax::mojom::StringAttribute::kHtmlId);
if (!id_attr.empty()) {
ADD_ATTRIBUTE("id", id_attr);
}
const auto& serialized_attrs = owner->GetHtmlAttributes();
for (const auto& serialized_attr : serialized_attrs) {
ADD_ATTRIBUTE(serialized_attr.first, serialized_attr.second);
}
*num_attribs = index;
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_attributesForNames(
USHORT num_attribs,
BSTR* attrib_names,
SHORT* name_space_id,
BSTR* attrib_values) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_ATTRIBUTES_FOR_NAMES);
return S_FALSE;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_computedStyle(
USHORT max_style_properties,
boolean use_alternate_view,
BSTR* style_properties,
BSTR* style_values,
USHORT* num_style_properties) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_COMPUTED_STYLE);
return E_NOTIMPL;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_computedStyleForProperties(
USHORT num_style_properties,
boolean use_alternate_view,
BSTR* style_properties,
BSTR* style_values) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_COMPUTED_STYLE_FOR_PROPERTIES);
return E_NOTIMPL;
}
IFACEMETHODIMP BrowserAccessibilityComWin::scrollTo(boolean placeTopLeft) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("scrollTo");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_ISIMPLEDOMNODE_SCROLL_TO);
return scrollTo(placeTopLeft ? IA2_SCROLL_TYPE_TOP_LEFT
: IA2_SCROLL_TYPE_ANYWHERE);
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_parentNode(
ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_parentNode");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_PARENT_NODE);
if (IsDestroyed()) {
return E_FAIL;
}
if (!node)
return E_INVALIDARG;
*node = ToBrowserAccessibilityComWin(GetOwner()->PlatformGetParent())
->NewReference();
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_firstChild(
ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_firstChild");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_FIRST_CHILD);
if (IsDestroyed()) {
return E_FAIL;
}
if (!node)
return E_INVALIDARG;
BrowserAccessibilityWin* const owner = GetOwner();
if (owner->PlatformChildCount() == 0) {
*node = NULL;
return S_FALSE;
}
*node = ToBrowserAccessibilityComWin(owner->PlatformGetFirstChild())
->NewReference();
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_lastChild(
ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_lastChild");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_LAST_CHILD);
if (IsDestroyed()) {
return E_FAIL;
}
if (!node)
return E_INVALIDARG;
BrowserAccessibilityWin* const owner = GetOwner();
if (owner->PlatformChildCount() == 0) {
*node = NULL;
return S_FALSE;
}
*node = ToBrowserAccessibilityComWin(owner->PlatformGetLastChild())
->NewReference();
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_previousSibling(
ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_previousSibling");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_PREVIOUS_SIBLING);
if (IsDestroyed()) {
return E_FAIL;
}
if (!node)
return E_INVALIDARG;
BrowserAccessibilityWin* const owner = GetOwner();
std::optional<size_t> index_in_parent = std::nullopt;
if (owner->PlatformGetParent()) {
index_in_parent = GetIndexInParent();
}
if (!index_in_parent.has_value() || index_in_parent.value() == 0) {
*node = NULL;
return S_FALSE;
}
*node = ToBrowserAccessibilityComWin(owner->InternalGetPreviousSibling())
->NewReference();
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_nextSibling(
ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_nextSibling");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_NEXT_SIBLING);
if (IsDestroyed()) {
return E_FAIL;
}
if (!node)
return E_INVALIDARG;
BrowserAccessibilityWin* const owner = GetOwner();
std::optional<size_t> index_in_parent = std::nullopt;
if (owner->PlatformGetParent()) {
index_in_parent = GetIndexInParent();
}
if (!index_in_parent.has_value() ||
(index_in_parent.value() + 1) >=
owner->PlatformGetParent()->InternalChildCount()) {
*node = NULL;
return S_FALSE;
}
*node = ToBrowserAccessibilityComWin(owner->InternalGetNextSibling())
->NewReference();
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_childAt(unsigned int child_index,
ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_childAt");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_CHILD_AT);
if (IsDestroyed()) {
return E_FAIL;
}
if (!node)
return E_INVALIDARG;
BrowserAccessibilityWin* const owner = GetOwner();
if (child_index >= owner->PlatformChildCount()) {
return E_INVALIDARG;
}
BrowserAccessibility* child = owner->PlatformGetChild(child_index);
if (!child) {
*node = NULL;
return S_FALSE;
}
*node = ToBrowserAccessibilityComWin(child)->NewReference();
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_innerHTML(BSTR* innerHTML) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_innerHTML");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_INNER_HTML);
if (IsDestroyed()) {
return E_FAIL;
}
if (!IsWebContent()) {
return E_FAIL;
}
OnExtendedPropertiesUsed();
BrowserAccessibilityWin* const owner = GetOwner();
if (owner->GetRole() != ax::mojom::Role::kMath &&
owner->GetRole() != ax::mojom::Role::kMathMLMath) {
return E_NOTIMPL;
}
std::u16string inner_html =
owner->GetString16Attribute(ax::mojom::StringAttribute::kMathContent);
*innerHTML = SysAllocString(base::as_wcstr(inner_html));
DCHECK(*innerHTML);
return S_OK;
}
IFACEMETHODIMP
BrowserAccessibilityComWin::get_localInterface(void** local_interface) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_localInterface");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_LOCAL_INTERFACE);
return E_NOTIMPL;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_language(BSTR* language) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_language");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_LANGUAGE);
if (IsDestroyed()) {
return E_FAIL;
}
if (!language) {
return E_INVALIDARG;
}
OnExtendedPropertiesUsed();
*language = nullptr;
std::wstring lang = base::UTF8ToWide(GetOwner()->node()->GetLanguage());
if (lang.empty())
lang = L"en-US";
*language = SysAllocString(lang.c_str());
DCHECK(*language);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_domText(BSTR* dom_text) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_domText");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_DOM_TEXT);
if (IsDestroyed()) {
return E_FAIL;
}
if (!dom_text)
return E_INVALIDARG;
return GetNameAsBstr(dom_text);
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_clippedSubstringBounds(
unsigned int start_index,
unsigned int end_index,
int* out_x,
int* out_y,
int* out_width,
int* out_height) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_clippedSubstringBounds");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_CLIPPED_SUBSTRING_BOUNDS);
if (IsDestroyed()) {
return E_FAIL;
}
OnInlineTextBoxesUsed();
return get_unclippedSubstringBounds(start_index, end_index, out_x, out_y,
out_width, out_height);
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_unclippedSubstringBounds(
unsigned int start_index,
unsigned int end_index,
int* out_x,
int* out_y,
int* out_width,
int* out_height) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_unclippedSubstringBounds");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_UNCLIPPED_SUBSTRING_BOUNDS);
if (IsDestroyed()) {
return E_FAIL;
}
if (!out_x || !out_y || !out_width || !out_height)
return E_INVALIDARG;
OnInlineTextBoxesUsed();
unsigned int text_length = static_cast<unsigned int>(GetHypertext().size());
if (start_index > text_length || end_index > text_length ||
start_index > end_index) {
return E_INVALIDARG;
}
gfx::Rect bounds = GetOwner()->GetScreenHypertextRangeBoundsRect(
start_index, end_index - start_index, AXClippingBehavior::kUnclipped);
*out_x = bounds.x();
*out_y = bounds.y();
*out_width = bounds.width();
*out_height = bounds.height();
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::scrollToSubstring(
unsigned int start_index,
unsigned int end_index) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("scrollToSubstring");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SCROLL_TO_SUBSTRING);
if (IsDestroyed()) {
return E_FAIL;
}
auto* manager = Manager();
if (!manager)
return E_FAIL;
OnInlineTextBoxesUsed();
unsigned int text_length = static_cast<unsigned int>(GetHypertext().size());
if (start_index > text_length || end_index > text_length ||
start_index > end_index) {
return E_INVALIDARG;
}
BrowserAccessibilityWin* const owner = GetOwner();
manager->ScrollToMakeVisible(*owner,
owner->GetRootFrameHypertextRangeBoundsRect(
start_index, end_index - start_index,
AXClippingBehavior::kUnclipped));
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::get_fontFamily(BSTR* font_family) {
WIN_ACCESSIBILITY_API_TRACE_EVENT("get_fontFamily");
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_FONT_FAMILY);
if (IsDestroyed()) {
return E_FAIL;
}
if (!font_family) {
return E_INVALIDARG;
}
OnExtendedPropertiesUsed();
*font_family = nullptr;
std::u16string family = GetOwner()->GetInheritedString16Attribute(
ax::mojom::StringAttribute::kFontFamily);
if (family.empty())
return S_FALSE;
*font_family = SysAllocString(base::as_wcstr(family));
DCHECK(*font_family);
return S_OK;
}
IFACEMETHODIMP BrowserAccessibilityComWin::QueryService(REFGUID guid_service,
REFIID riid,
void** object) {
TRACE_EVENT("accessibility", "QueryService",
perfetto::Flow::FromPointer(this), "guidService",
base::WideToASCII(base::win::WStringFromGUID(guid_service)),
"riid", base::WideToASCII(base::win::WStringFromGUID(riid)));
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_QUERY_SERVICE);
if (IsDestroyed()) {
return E_FAIL;
}
if (guid_service == GUID_IAccessibleContentDocument) {
BrowserAccessibility* node = GetOwner();
while (node->PlatformGetParent())
node =
node->PlatformGetParent()->manager()->GetBrowserAccessibilityRoot();
return ToBrowserAccessibilityComWin(node)->QueryInterface(IID_IAccessible2,
object);
}
if (guid_service == IID_IAccessible || guid_service == IID_IAccessible2 ||
guid_service == IID_IAccessibleAction ||
guid_service == IID_IAccessibleApplication ||
guid_service == IID_IAccessibleHyperlink ||
guid_service == IID_IAccessibleHypertext ||
guid_service == IID_IAccessibleImage ||
guid_service == IID_IAccessibleTable ||
guid_service == IID_IAccessibleTable2 ||
guid_service == IID_IAccessibleTableCell ||
guid_service == IID_IAccessibleText ||
guid_service == IID_IAccessibleTextSelectionContainer ||
guid_service == IID_IAccessibleValue ||
guid_service == IID_ISimpleDOMDocument ||
guid_service == IID_ISimpleDOMNode ||
guid_service == IID_ISimpleDOMText || guid_service == GUID_ISimpleDOM) {
return QueryInterface(riid, object);
}
*object = NULL;
return E_FAIL;
}
STDMETHODIMP BrowserAccessibilityComWin::InternalQueryInterface(
void* this_ptr,
const _ATL_INTMAP_ENTRY* entries,
REFIID iid,
void** object) {
BrowserAccessibilityComWin* accessibility =
reinterpret_cast<BrowserAccessibilityComWin*>(this_ptr);
if (!accessibility || accessibility->IsDestroyed()) {
*object = nullptr;
return E_NOINTERFACE;
}
if (iid == IID_IAccessibleImage) {
const ax::mojom::Role role = accessibility->GetOwner()->GetRole();
if (!IsImage(role)) {
*object = nullptr;
return E_NOINTERFACE;
}
} else if (iid == IID_ISimpleDOMDocument) {
if (!ui::IsPlatformDocument(accessibility->GetRole())) {
*object = nullptr;
return E_NOINTERFACE;
}
} else if (iid == IID_IAccessibleHyperlink) {
if (!accessibility->IsHyperlink()) {
*object = nullptr;
return E_NOINTERFACE;
}
}
return AXPlatformNodeWin::InternalQueryInterface(this_ptr, entries, iid,
object);
}
void BrowserAccessibilityComWin::ComputeStylesIfNeeded() {
if (!offset_to_text_attributes().empty())
return;
TextAttributeList default_attributes =
AXPlatformNodeWin::ComputeTextAttributes();
TextAttributeMap attributes_map =
GetDelegate()->ComputeTextAttributeMap(default_attributes);
win_attributes_->offset_to_text_attributes.swap(attributes_map);
}
void BrowserAccessibilityComWin::UpdateStep1ComputeWinAttributes(
UpdateState* update_state) {
DCHECK(!update_state_);
DCHECK(win_attributes_);
BrowserAccessibilityWin* const owner = GetOwner();
update_state->old_win_attributes = std::move(win_attributes_);
update_state->old_hypertext = std::move(hypertext_);
update_state_ = update_state;
hypertext_ = AXLegacyHypertext();
win_attributes_ = std::make_unique<WinAttributes>();
win_attributes_->ia_role = MSAARole();
win_attributes_->ia_state = MSAAState();
win_attributes_->ia2_role = ComputeIA2Role();
if (!win_attributes_->ia2_role)
win_attributes_->ia2_role = win_attributes_->ia_role;
win_attributes_->ia2_state = ComputeIA2State();
win_attributes_->name = base::UTF8ToWide(owner->GetName());
win_attributes_->description = base::UTF8ToWide(
owner->GetStringAttribute(ax::mojom::StringAttribute::kDescription));
win_attributes_->value = base::UTF16ToWide(GetValueForControl());
win_attributes_->ignored = owner->IsIgnored();
}
void BrowserAccessibilityComWin::UpdateStep2ComputeHypertext() {
DCHECK(update_state_);
UpdateComputedHypertext();
}
void BrowserAccessibilityComWin::UpdateStep3FireEvents() {
DCHECK(update_state_);
DCHECK(update_state_->old_win_attributes);
BrowserAccessibilityWin* const owner = GetOwner();
const bool ignored = owner->IsIgnored();
const auto& old_win_attributes = *update_state_->old_win_attributes;
if (ignored || (old_win_attributes.ignored != ignored &&
!owner->GetData().IsContainedInActiveLiveRegion() &&
!owner->GetData().IsActiveLiveRegionRoot())) {
update_state_ = nullptr;
return;
}
if (old_win_attributes.ia_role != 0) {
if (description() != old_win_attributes.description) {
FireNativeEvent(EVENT_OBJECT_DESCRIPTIONCHANGE);
}
int sx = 0;
int sy = 0;
if (owner->GetIntAttribute(ax::mojom::IntAttribute::kScrollX, &sx) &&
owner->GetIntAttribute(ax::mojom::IntAttribute::kScrollY, &sy)) {
if (sx != previous_scroll_x_ || sy != previous_scroll_y_)
FireNativeEvent(EVENT_SYSTEM_SCROLLINGEND);
previous_scroll_x_ = sx;
previous_scroll_y_ = sy;
}
if (name() == old_win_attributes.name ||
GetNameFrom() == ax::mojom::NameFrom::kContents) {
size_t start, old_len, new_len;
ComputeHypertextRemovedAndInserted(update_state_->old_hypertext, &start,
&old_len, &new_len);
if (old_len > 0) {
FireNativeEvent(IA2_EVENT_TEXT_REMOVED);
}
if (new_len > 0) {
FireNativeEvent(IA2_EVENT_TEXT_INSERTED);
}
}
}
update_state_ = nullptr;
}
BrowserAccessibilityWin* BrowserAccessibilityComWin::GetOwner() const {
return static_cast<BrowserAccessibilityWin*>(GetDelegate());
}
BrowserAccessibilityManager* BrowserAccessibilityComWin::Manager() const {
auto* manager = GetOwner()->manager();
DCHECK(manager);
return manager;
}
BrowserAccessibilityComWin* BrowserAccessibilityComWin::NewReference() {
AddRef();
return this;
}
BrowserAccessibilityComWin* BrowserAccessibilityComWin::GetTargetFromChildID(
const VARIANT& var_id) {
if (IsDestroyed()) {
return nullptr;
}
if (var_id.vt != VT_I4)
return nullptr;
LONG child_id = var_id.lVal;
if (child_id == CHILDID_SELF)
return this;
BrowserAccessibilityWin* const owner = GetOwner();
if (child_id >= 1 &&
child_id <= static_cast<LONG>(owner->PlatformChildCount())) {
return ToBrowserAccessibilityComWin(owner->PlatformGetChild(child_id - 1));
}
auto* child = static_cast<BrowserAccessibilityComWin*>(
AXPlatformNodeWin::GetFromUniqueId(-child_id));
if (child && child->GetOwner()->IsDescendantOf(owner)) {
return child;
}
return nullptr;
}
HRESULT BrowserAccessibilityComWin::GetStringAttributeAsBstr(
ax::mojom::StringAttribute attribute,
BSTR* value_bstr) {
if (IsDestroyed()) {
return E_FAIL;
}
std::u16string str;
if (!GetOwner()->GetString16Attribute(attribute, &str)) {
return S_FALSE;
}
*value_bstr = SysAllocString(base::as_wcstr(str));
DCHECK(*value_bstr);
return S_OK;
}
HRESULT BrowserAccessibilityComWin::GetNameAsBstr(BSTR* value_bstr) {
if (IsDestroyed()) {
return E_FAIL;
}
std::u16string str;
str = GetOwner()->GetNameAsString16();
*value_bstr = SysAllocString(base::as_wcstr(str));
DCHECK(*value_bstr);
return S_OK;
}
void BrowserAccessibilityComWin::SetIA2HypertextSelection(LONG start_offset,
LONG end_offset) {
HandleSpecialTextOffset(&start_offset);
HandleSpecialTextOffset(&end_offset);
SetHypertextSelection(start_offset, end_offset);
}
LONG BrowserAccessibilityComWin::FindStartOfStyle(
LONG start_offset,
ax::mojom::MoveDirection direction) {
LONG text_length = static_cast<LONG>(GetHypertext().length());
DCHECK_GE(start_offset, 0);
DCHECK_LE(start_offset, text_length);
switch (direction) {
case ax::mojom::MoveDirection::kNone:
NOTREACHED();
case ax::mojom::MoveDirection::kBackward: {
if (offset_to_text_attributes().empty())
return 0;
auto iterator = offset_to_text_attributes().upper_bound(start_offset);
--iterator;
return static_cast<LONG>(iterator->first);
}
case ax::mojom::MoveDirection::kForward: {
const auto iterator =
offset_to_text_attributes().upper_bound(start_offset);
if (iterator == offset_to_text_attributes().end())
return text_length;
return static_cast<LONG>(iterator->first);
}
}
NOTREACHED();
}
BrowserAccessibilityComWin* BrowserAccessibilityComWin::GetFromID(
int32_t id) const {
if (IsDestroyed()) {
return nullptr;
}
return ToBrowserAccessibilityComWin(Manager()->GetFromID(id));
}
void BrowserAccessibilityComWin::FireNativeEvent(LONG win_event_type) const {
BrowserAccessibilityWin* const owner = GetOwner();
if (owner->IsChildOfLeaf() && !owner->GetCollapsedMenuListSelectAncestor()) {
return;
}
Manager()->ToBrowserAccessibilityManagerWin()->FireWinAccessibilityEvent(
win_event_type, owner);
}
BrowserAccessibilityComWin* ToBrowserAccessibilityComWin(
BrowserAccessibility* obj) {
if (!obj)
return nullptr;
auto* result = static_cast<BrowserAccessibilityWin*>(obj)->GetCOM();
return result;
}
}