Commit e0fd1008 authored by Joanmarie Diggs's avatar Joanmarie Diggs Committed by Commit Bot

Ensure we have native text control ancestor in AXSelection::Select

AXSelection::Select has logic meant to handle selection within an native
text field. But when the selection is being set, the base and extent may
be the static text descendant of the AXObject associated with the field.
In this instance, the logic for text fields is not being used.

Fix this by retrieving the native text control ancestor AXObject. Then,
to ensure there is no behavior change, set focus on the element after
the selection range was successfully set.

Bug: 1113650

AX-Relnotes: N/A
Change-Id: I5b1db3dcf7d01baf971d5858c936a4e5d168543e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2352898
Commit-Queue: Joanmarie Diggs <jdiggs@igalia.com>
Reviewed-by: default avatarNektarios Paisios <nektar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#800297}
parent d25ea9f6
......@@ -1555,6 +1555,20 @@ bool AXObject::ComputeAccessibilityIsIgnoredButIncludedInTree() const {
return false;
}
const AXObject* AXObject::GetNativeTextControlAncestor(
int max_levels_to_check) const {
if (IsNativeTextControl())
return this;
if (max_levels_to_check == 0)
return nullptr;
if (AXObject* parent = ParentObject())
return parent->GetNativeTextControlAncestor(max_levels_to_check - 1);
return nullptr;
}
const AXObject* AXObject::DatetimeAncestor(int max_levels_to_check) const {
switch (RoleValue()) {
case ax::mojom::blink::Role::kDateTime:
......
......@@ -538,6 +538,8 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
AXObject* LeafNodeAncestor() const;
bool IsDescendantOfDisabledNode() const;
bool ComputeAccessibilityIsIgnoredButIncludedInTree() const;
const AXObject* GetNativeTextControlAncestor(
int max_levels_to_check = 3) const;
const AXObject* DatetimeAncestor(int max_levels_to_check = 3) const;
const AXObject* DisabledAncestor() const;
bool LastKnownIsIgnoredValue() const;
......
......@@ -339,15 +339,18 @@ bool AXSelection::Select(const AXSelectionBehavior selection_behavior) {
AsTextControlSelection();
if (text_control_selection.has_value()) {
DCHECK_LE(text_control_selection->start, text_control_selection->end);
TextControlElement& text_control =
ToTextControl(*base_.ContainerObject()->GetNode());
TextControlElement& text_control = ToTextControl(
*base_.ContainerObject()->GetNativeTextControlAncestor()->GetNode());
if (!text_control.SetSelectionRange(text_control_selection->start,
text_control_selection->end,
text_control_selection->direction)) {
return false;
}
// TextControl::SetSelectionRange deliberately does not set focus. But if
// we're updating the selection, the text control should be focused.
ScheduleSelectEvent(text_control);
text_control.focus();
return true;
}
......@@ -423,19 +426,23 @@ String AXSelection::ToString() const {
base::Optional<AXSelection::TextControlSelection>
AXSelection::AsTextControlSelection() const {
if (!IsValid() || !base_.IsTextPosition() || !extent_.IsTextPosition() ||
base_.ContainerObject() != extent_.ContainerObject() ||
!base_.ContainerObject()->IsNativeTextControl() ||
!IsTextControl(base_.ContainerObject()->GetNode())) {
base_.ContainerObject() != extent_.ContainerObject()) {
return {};
}
const AXObject* text_control =
base_.ContainerObject()->GetNativeTextControlAncestor();
if (!text_control)
return {};
DCHECK(IsTextControl(text_control->GetNode()));
if (base_ <= extent_) {
return TextControlSelection(base_.TextOffset(), extent_.TextOffset(),
kSelectionHasForwardDirection);
} else {
return TextControlSelection(extent_.TextOffset(), base_.TextOffset(),
kSelectionHasBackwardDirection);
}
return TextControlSelection(extent_.TextOffset(), base_.TextOffset(),
kSelectionHasBackwardDirection);
}
bool operator==(const AXSelection& a, const AXSelection& b) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment