blob: d54b1a0e9841b263879d5b9ad4b95642e2eeaf25 [file] [log] [blame]
// Copyright 2016 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 file.
#include "content/browser/accessibility/browser_accessibility_position.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/buildflags.h"
namespace content {
BrowserAccessibilityPosition::BrowserAccessibilityPosition() = default;
BrowserAccessibilityPosition::~BrowserAccessibilityPosition() = default;
BrowserAccessibilityPosition::BrowserAccessibilityPosition(
const BrowserAccessibilityPosition& other)
: ui::AXPosition<BrowserAccessibilityPosition, BrowserAccessibility>(
other) {}
BrowserAccessibilityPosition::AXPositionInstance
BrowserAccessibilityPosition::Clone() const {
return AXPositionInstance(new BrowserAccessibilityPosition(*this));
}
base::string16 BrowserAccessibilityPosition::GetText() const {
if (IsNullPosition())
return {};
DCHECK(GetAnchor());
return GetAnchor()->GetText();
}
bool BrowserAccessibilityPosition::IsInLineBreak() const {
if (IsNullPosition())
return false;
DCHECK(GetAnchor());
return GetAnchor()->IsLineBreakObject();
}
bool BrowserAccessibilityPosition::IsInTextObject() const {
if (IsNullPosition())
return false;
DCHECK(GetAnchor());
return GetAnchor()->IsText();
}
bool BrowserAccessibilityPosition::IsInWhiteSpace() const {
if (IsNullPosition())
return false;
DCHECK(GetAnchor());
return GetAnchor()->IsLineBreakObject() ||
base::ContainsOnlyChars(GetText(), base::kWhitespaceUTF16);
}
void BrowserAccessibilityPosition::AnchorChild(
int child_index,
AXTreeID* tree_id,
ui::AXNode::AXID* child_id) const {
DCHECK(tree_id);
DCHECK(child_id);
if (!GetAnchor() || child_index < 0 || child_index >= AnchorChildCount()) {
*tree_id = ui::AXTreeIDUnknown();
*child_id = ui::AXNode::kInvalidAXID;
return;
}
BrowserAccessibility* child = nullptr;
if (GetAnchor()->PlatformIsLeaf()) {
child = GetAnchor()->InternalGetChild(child_index);
} else {
child = GetAnchor()->PlatformGetChild(child_index);
}
DCHECK(child);
*tree_id = child->manager()->ax_tree_id();
*child_id = child->GetId();
}
int BrowserAccessibilityPosition::AnchorChildCount() const {
if (!GetAnchor())
return 0;
if (GetAnchor()->PlatformIsLeaf()) {
return static_cast<int>(GetAnchor()->InternalChildCount());
} else {
return static_cast<int>(GetAnchor()->PlatformChildCount());
}
}
int BrowserAccessibilityPosition::AnchorUnignoredChildCount() const {
if (!GetAnchor())
return 0;
return static_cast<int>(GetAnchor()->InternalChildCount());
}
int BrowserAccessibilityPosition::AnchorIndexInParent() const {
return GetAnchor() ? GetAnchor()->GetIndexInParent()
: AXPosition::INVALID_INDEX;
}
int BrowserAccessibilityPosition::AnchorSiblingCount() const {
BrowserAccessibility* parent = GetAnchor()->PlatformGetParent();
if (parent)
return static_cast<int>(parent->InternalChildCount());
return 0;
}
base::stack<BrowserAccessibility*>
BrowserAccessibilityPosition::GetAncestorAnchors() const {
base::stack<BrowserAccessibility*> anchors;
BrowserAccessibility* current_anchor = GetAnchor();
while (current_anchor) {
anchors.push(current_anchor);
current_anchor = current_anchor->PlatformGetParent();
}
return anchors;
}
BrowserAccessibility* BrowserAccessibilityPosition::GetLowestUnignoredAncestor()
const {
if (!GetAnchor())
return nullptr;
return GetAnchor()->PlatformGetParent();
}
void BrowserAccessibilityPosition::AnchorParent(
AXTreeID* tree_id,
ui::AXNode::AXID* parent_id) const {
DCHECK(tree_id);
DCHECK(parent_id);
if (!GetAnchor() || !GetAnchor()->PlatformGetParent()) {
*tree_id = ui::AXTreeIDUnknown();
*parent_id = ui::AXNode::kInvalidAXID;
return;
}
BrowserAccessibility* parent = GetAnchor()->PlatformGetParent();
*tree_id = parent->manager()->ax_tree_id();
*parent_id = parent->GetId();
}
BrowserAccessibility* BrowserAccessibilityPosition::GetNodeInTree(
AXTreeID tree_id,
ui::AXNode::AXID node_id) const {
if (tree_id == ui::AXTreeIDUnknown() || node_id == ui::AXNode::kInvalidAXID) {
return nullptr;
}
auto* manager = BrowserAccessibilityManager::FromID(tree_id);
if (!manager)
return nullptr;
return manager->GetFromID(node_id);
}
int32_t BrowserAccessibilityPosition::GetAnchorID(
BrowserAccessibility* node) const {
return node->GetId();
}
AXTreeID BrowserAccessibilityPosition::GetTreeID(
BrowserAccessibility* node) const {
return node->manager()->ax_tree_id();
}
bool BrowserAccessibilityPosition::IsEmbeddedObjectInParent() const {
// On some platforms, most objects are represented in the text of their
// parents with a special (embedded object) character and not with their
// actual text contents.
#if defined(OS_WIN) || BUILDFLAG(USE_ATK)
// Not all objects in the internal accessibility tree are exposed to platform
// APIs.
return !IsNullPosition() && !GetAnchor()->IsText() &&
!GetAnchor()->IsChildOfLeaf();
#else
return false;
#endif
}
bool BrowserAccessibilityPosition::IsInLineBreakingObject() const {
if (IsNullPosition())
return false;
DCHECK(GetAnchor());
return GetAnchor()->GetBoolAttribute(
ax::mojom::BoolAttribute::kIsLineBreakingObject) &&
!GetAnchor()->IsInListMarker();
}
ax::mojom::Role BrowserAccessibilityPosition::GetAnchorRole() const {
if (IsNullPosition())
return ax::mojom::Role::kNone;
DCHECK(GetAnchor());
return GetRole(GetAnchor());
}
ax::mojom::Role BrowserAccessibilityPosition::GetRole(
BrowserAccessibility* node) const {
return node->GetRole();
}
ui::AXNodeTextStyles BrowserAccessibilityPosition::GetTextStyles() const {
// Check either the current anchor or its parent for text styles.
ui::AXNodeTextStyles current_anchor_text_styles =
!IsNullPosition() ? GetAnchor()->GetData().GetTextStyles()
: ui::AXNodeTextStyles();
if (current_anchor_text_styles.IsUnset()) {
AXPositionInstance parent = CreateParentPosition();
if (!parent->IsNullPosition())
return parent->GetAnchor()->GetData().GetTextStyles();
}
return current_anchor_text_styles;
}
std::vector<int32_t> BrowserAccessibilityPosition::GetWordStartOffsets() const {
if (IsNullPosition())
return std::vector<int32_t>();
DCHECK(GetAnchor());
return GetAnchor()->GetIntListAttribute(
ax::mojom::IntListAttribute::kWordStarts);
}
std::vector<int32_t> BrowserAccessibilityPosition::GetWordEndOffsets() const {
if (IsNullPosition())
return std::vector<int32_t>();
DCHECK(GetAnchor());
return GetAnchor()->GetIntListAttribute(
ax::mojom::IntListAttribute::kWordEnds);
}
ui::AXNode::AXID BrowserAccessibilityPosition::GetNextOnLineID(
ui::AXNode::AXID node_id) const {
if (IsNullPosition())
return ui::AXNode::kInvalidAXID;
BrowserAccessibility* node = GetNodeInTree(tree_id(), node_id);
int next_on_line_id;
if (!node || !node->GetIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
&next_on_line_id)) {
return ui::AXNode::kInvalidAXID;
}
return static_cast<ui::AXNode::AXID>(next_on_line_id);
}
ui::AXNode::AXID BrowserAccessibilityPosition::GetPreviousOnLineID(
ui::AXNode::AXID node_id) const {
if (IsNullPosition())
return ui::AXNode::kInvalidAXID;
BrowserAccessibility* node = GetNodeInTree(tree_id(), node_id);
int previous_on_line_id;
if (!node ||
!node->GetIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
&previous_on_line_id)) {
return ui::AXNode::kInvalidAXID;
}
return static_cast<ui::AXNode::AXID>(previous_on_line_id);
}
} // namespace content