#include "ui/accessibility/ax_selection.h"
#include "ui/accessibility/ax_node_position.h"
namespace ui {
namespace {
bool ComputeUnignoredSelectionEndpoint(
const AXTree* tree,
AXPositionAdjustmentBehavior adjustment_behavior,
AXNodeID& node_id,
int32_t& offset,
ax::mojom::TextAffinity& affinity) {
AXNode* node = tree ? tree->GetFromId(node_id) : nullptr;
if (!node) {
node_id = kInvalidAXNodeID;
offset = AXNodePosition::INVALID_OFFSET;
affinity = ax::mojom::TextAffinity::kDownstream;
return false;
}
AXNodePosition::AXPositionInstance position =
AXNodePosition::CreatePosition(*node, offset, affinity);
if (!position->IsIgnored()) {
return true;
}
position =
position->AsValidPosition()->AsUnignoredPosition(adjustment_behavior);
if (position->IsLeafTreePosition())
position = position->AsTextPosition();
if (position->IsTextPosition() &&
position->GetRole() == ax::mojom::Role::kInlineTextBox) {
position = position->CreateParentPosition();
}
switch (position->kind()) {
case AXPositionKind::NULL_POSITION:
node_id = kInvalidAXNodeID;
offset = AXNodePosition::INVALID_OFFSET;
affinity = ax::mojom::TextAffinity::kDownstream;
return false;
case AXPositionKind::TREE_POSITION:
node_id = position->anchor_id();
offset = position->child_index();
affinity = ax::mojom::TextAffinity::kDownstream;
return true;
case AXPositionKind::TEXT_POSITION:
node_id = position->anchor_id();
offset = position->text_offset();
affinity = position->affinity();
return true;
}
}
}
AXSelection::AXSelection() = default;
AXSelection::AXSelection(const AXSelection&) = default;
AXSelection::~AXSelection() = default;
AXSelection::AXSelection(const AXTree& tree)
: is_backward(tree.data().sel_is_backward),
anchor_object_id(tree.data().sel_anchor_object_id),
anchor_offset(tree.data().sel_anchor_offset),
anchor_affinity(tree.data().sel_anchor_affinity),
focus_object_id(tree.data().sel_focus_object_id),
focus_offset(tree.data().sel_focus_offset),
focus_affinity(tree.data().sel_focus_affinity),
tree_id_(tree.GetAXTreeID()) {}
AXSelection& AXSelection::ToUnignoredSelection() {
const AXTreeManager* manager = AXTreeManager::FromID(tree_id_);
if (!manager)
return *this;
if (!ComputeUnignoredSelectionEndpoint(
manager->ax_tree(),
is_backward ? AXPositionAdjustmentBehavior::kMoveForward
: AXPositionAdjustmentBehavior::kMoveBackward,
anchor_object_id, anchor_offset, anchor_affinity)) {
focus_object_id = kInvalidAXNodeID;
focus_offset = AXNodePosition::INVALID_OFFSET;
focus_affinity = ax::mojom::TextAffinity::kDownstream;
} else if (!ComputeUnignoredSelectionEndpoint(
manager->ax_tree(),
is_backward ? AXPositionAdjustmentBehavior::kMoveBackward
: AXPositionAdjustmentBehavior::kMoveForward,
focus_object_id, focus_offset, focus_affinity)) {
anchor_object_id = kInvalidAXNodeID;
anchor_offset = AXNodePosition::INVALID_OFFSET;
anchor_affinity = ax::mojom::TextAffinity::kDownstream;
}
return *this;
}
}