#include "ui/accessibility/ax_node_position.h"
#include "base/containers/fixed_flat_map.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/base/buildflags.h"
namespace ui {
AXEmbeddedObjectBehavior g_ax_embedded_object_behavior =
#if BUILDFLAG(IS_WIN) || BUILDFLAG(USE_ATK)
AXEmbeddedObjectBehavior::kExposeCharacterForHypertext;
#else
AXEmbeddedObjectBehavior::kSuppressCharacter;
#endif
ScopedAXEmbeddedObjectBehaviorSetter::ScopedAXEmbeddedObjectBehaviorSetter(
AXEmbeddedObjectBehavior behavior) {
prev_behavior_ = g_ax_embedded_object_behavior;
g_ax_embedded_object_behavior = behavior;
}
ScopedAXEmbeddedObjectBehaviorSetter::~ScopedAXEmbeddedObjectBehaviorSetter() {
g_ax_embedded_object_behavior = prev_behavior_;
}
std::string ToString(const AXPositionKind kind) {
static constexpr auto kKindToString =
base::MakeFixedFlatMap<AXPositionKind, const char*>(
{{AXPositionKind::NULL_POSITION, "NullPosition"},
{AXPositionKind::TREE_POSITION, "TreePosition"},
{AXPositionKind::TEXT_POSITION, "TextPosition"}});
const auto iter = kKindToString.find(kind);
if (iter == std::end(kKindToString))
return std::string();
return iter->second;
}
AXNodePosition::AXPositionInstance AXNodePosition::CreatePosition(
const AXNode& node,
int child_index_or_text_offset,
ax::mojom::TextAffinity affinity) {
if (!node.tree())
return CreateNullPosition();
if (IsTextPositionAnchor(node)) {
int text_offset = child_index_or_text_offset == BEFORE_TEXT
? 0
: child_index_or_text_offset;
return CreateTextPosition(node, text_offset, affinity);
}
DCHECK_LE(child_index_or_text_offset,
static_cast<int>(node.GetChildCountCrossingTreeBoundary()))
<< "\n* Trying to create a tree position with a child index that is too "
"large. Maybe a text position should have been created instead?\n"
<< "\n* Anchor node: " << node << "\n* IsLeaf(): " << node.IsLeaf()
<< "\n* Child offset: " << child_index_or_text_offset
<< "\n* IsLeafNodeForTreePosition(): " << IsLeafNodeForTreePosition(node)
<< "\n* Tree: " << node.tree()->ToString();
return CreateTreePosition(node, child_index_or_text_offset);
}
bool AXNodePosition::IsTextPositionAnchor(const AXNode& node) {
if (node.IsLeaf())
return true;
if (IsLeafNodeForTreePosition(node))
return true;
if (node.GetRole() == ax::mojom::Role::kSpinButton) {
return true;
}
if (node.data().IsAtomicTextField()) {
DCHECK(node.IsIgnored()) << "Returned false from IsLeaf(): " << node;
return true;
}
return false;
}
AXNodePosition::AXNodePosition() = default;
AXNodePosition::~AXNodePosition() = default;
AXNodePosition::AXNodePosition(const AXNodePosition& other) = default;
AXNodePosition::AXPositionInstance AXNodePosition::Clone() const {
return AXPositionInstance(new AXNodePosition(*this));
}
}