Commit c6061510 authored by Nektarios Paisios's avatar Nektarios Paisios Committed by Commit Bot

AXSelection: Added a method to retrieve the legacy text control selection

Required by existing browser code which we should remove if we can.
R=dmazzoni@chromium.org, aleventhal@chromium.org

Change-Id: I42312c4a21a80f95dd44179465f9689852fbd41c
Reviewed-on: https://chromium-review.googlesource.com/c/1370494Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Commit-Queue: Nektarios Paisios <nektar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#615646}
parent 6ea010eb
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "third_party/blink/renderer/core/editing/text_affinity.h" #include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object.h" #include "third_party/blink/renderer/modules/accessibility/ax_object.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
namespace blink { namespace blink {
...@@ -119,11 +120,11 @@ void AXSelection::ClearCurrentSelection(Document& document) { ...@@ -119,11 +120,11 @@ void AXSelection::ClearCurrentSelection(Document& document) {
AXSelection AXSelection::FromCurrentSelection( AXSelection AXSelection::FromCurrentSelection(
const Document& document, const Document& document,
const AXSelectionBehavior selection_behavior) { const AXSelectionBehavior selection_behavior) {
LocalFrame* frame = document.GetFrame(); const LocalFrame* frame = document.GetFrame();
if (!frame) if (!frame)
return {}; return {};
FrameSelection& frame_selection = frame->Selection(); const FrameSelection& frame_selection = frame->Selection();
if (!frame_selection.IsAvailable()) if (!frame_selection.IsAvailable())
return {}; return {};
...@@ -131,6 +132,30 @@ AXSelection AXSelection::FromCurrentSelection( ...@@ -131,6 +132,30 @@ AXSelection AXSelection::FromCurrentSelection(
selection_behavior); selection_behavior);
} }
// static
AXSelection AXSelection::FromCurrentSelection(
const TextControlElement& text_control) {
const Document& document = text_control.GetDocument();
AXObjectCache* ax_object_cache = document.ExistingAXObjectCache();
if (!ax_object_cache)
return {};
auto* ax_object_cache_impl = static_cast<AXObjectCacheImpl*>(ax_object_cache);
const AXObject* ax_text_control =
ax_object_cache_impl->GetOrCreate(&text_control);
DCHECK(ax_text_control);
const TextAffinity affinity = text_control.Selection().Affinity();
const auto ax_base = AXPosition::CreatePositionInTextObject(
*ax_text_control, static_cast<int>(text_control.selectionStart()));
const auto ax_extent = AXPosition::CreatePositionInTextObject(
*ax_text_control, static_cast<int>(text_control.selectionEnd()),
affinity);
AXSelection::Builder selection_builder;
selection_builder.SetBase(ax_base).SetExtent(ax_extent);
return selection_builder.Build();
}
// static // static
AXSelection AXSelection::FromSelection( AXSelection AXSelection::FromSelection(
const SelectionInDOMTree& selection, const SelectionInDOMTree& selection,
......
...@@ -47,6 +47,8 @@ class MODULES_EXPORT AXSelection final { ...@@ -47,6 +47,8 @@ class MODULES_EXPORT AXSelection final {
const Document&, const Document&,
const AXSelectionBehavior = AXSelectionBehavior::kExtendToValidDOMRange); const AXSelectionBehavior = AXSelectionBehavior::kExtendToValidDOMRange);
static AXSelection FromCurrentSelection(const TextControlElement&);
static AXSelection FromSelection( static AXSelection FromSelection(
const SelectionInDOMTree&, const SelectionInDOMTree&,
const AXSelectionBehavior = AXSelectionBehavior::kExtendToValidDOMRange); const AXSelectionBehavior = AXSelectionBehavior::kExtendToValidDOMRange);
......
...@@ -438,6 +438,158 @@ TEST_F(AccessibilitySelectionTest, SetSelectionAroundListBullet) { ...@@ -438,6 +438,158 @@ TEST_F(AccessibilitySelectionTest, SetSelectionAroundListBullet) {
// Tests that involve selection inside, outside, and spanning text controls. // Tests that involve selection inside, outside, and spanning text controls.
// //
TEST_F(AccessibilitySelectionTest, FromCurrentSelectionInTextField) {
GetPage().GetSettings().SetScriptEnabled(true);
SetBodyInnerHTML(R"HTML(
<input id="input" value="Inside text field.">
)HTML");
ASSERT_FALSE(AXSelection::FromCurrentSelection(GetDocument()).IsValid());
Element* const script_element =
GetDocument().CreateRawElement(html_names::kScriptTag);
ASSERT_NE(nullptr, script_element);
script_element->setTextContent(R"SCRIPT(
let input = document.querySelector('input');
input.focus();
input.selectionStart = 0;
input.selectionEnd = input.value.length;
)SCRIPT");
GetDocument().body()->AppendChild(script_element);
UpdateAllLifecyclePhasesForTest();
const Element* input = GetDocument().QuerySelector("input");
ASSERT_NE(nullptr, input);
ASSERT_TRUE(IsTextControl(input));
const AXObject* ax_input = GetAXObjectByElementId("input");
ASSERT_NE(nullptr, ax_input);
ASSERT_EQ(ax::mojom::Role::kTextField, ax_input->RoleValue());
const auto ax_selection =
AXSelection::FromCurrentSelection(ToTextControl(*input));
ASSERT_TRUE(ax_selection.IsValid());
EXPECT_TRUE(ax_selection.Base().IsTextPosition());
EXPECT_EQ(ax_input, ax_selection.Base().ContainerObject());
EXPECT_EQ(0, ax_selection.Base().TextOffset());
EXPECT_TRUE(ax_selection.Extent().IsTextPosition());
EXPECT_EQ(ax_input, ax_selection.Extent().ContainerObject());
EXPECT_EQ(18, ax_selection.Extent().TextOffset());
}
TEST_F(AccessibilitySelectionTest, FromCurrentSelectionInTextarea) {
GetPage().GetSettings().SetScriptEnabled(true);
SetBodyInnerHTML(R"HTML(
<textarea id="textarea">
Inside
textarea
field.
</textarea>
)HTML");
ASSERT_FALSE(AXSelection::FromCurrentSelection(GetDocument()).IsValid());
Element* const script_element =
GetDocument().CreateRawElement(html_names::kScriptTag);
ASSERT_NE(nullptr, script_element);
script_element->setTextContent(R"SCRIPT(
let textarea = document.querySelector('textarea');
textarea.focus();
textarea.selectionStart = 0;
textarea.selectionEnd = textarea.textLength;
)SCRIPT");
GetDocument().body()->AppendChild(script_element);
UpdateAllLifecyclePhasesForTest();
const Element* textarea = GetDocument().QuerySelector("textarea");
ASSERT_NE(nullptr, textarea);
ASSERT_TRUE(IsTextControl(textarea));
const AXObject* ax_textarea = GetAXObjectByElementId("textarea");
ASSERT_NE(nullptr, ax_textarea);
ASSERT_EQ(ax::mojom::Role::kTextField, ax_textarea->RoleValue());
const auto ax_selection =
AXSelection::FromCurrentSelection(ToTextControl(*textarea));
ASSERT_TRUE(ax_selection.IsValid());
EXPECT_TRUE(ax_selection.Base().IsTextPosition());
EXPECT_EQ(ax_textarea, ax_selection.Base().ContainerObject());
EXPECT_EQ(0, ax_selection.Base().TextOffset());
EXPECT_TRUE(ax_selection.Extent().IsTextPosition());
EXPECT_EQ(ax_textarea, ax_selection.Extent().ContainerObject());
EXPECT_EQ(53, ax_selection.Extent().TextOffset());
}
TEST_F(AccessibilitySelectionTest, ClearCurrentSelectionInTextField) {
GetPage().GetSettings().SetScriptEnabled(true);
SetBodyInnerHTML(R"HTML(
<input id="input" value="Inside text field.">
)HTML");
ASSERT_FALSE(AXSelection::FromCurrentSelection(GetDocument()).IsValid());
Element* const script_element =
GetDocument().CreateRawElement(html_names::kScriptTag);
ASSERT_NE(nullptr, script_element);
script_element->setTextContent(R"SCRIPT(
let input = document.querySelector('input');
input.focus();
input.selectionStart = 0;
input.selectionEnd = input.textLength;
)SCRIPT");
GetDocument().body()->AppendChild(script_element);
UpdateAllLifecyclePhasesForTest();
SelectionInDOMTree selection = Selection().GetSelectionInDOMTree();
ASSERT_FALSE(selection.IsNone());
AXSelection::ClearCurrentSelection(GetDocument());
selection = Selection().GetSelectionInDOMTree();
EXPECT_TRUE(selection.IsNone());
const auto ax_selection = AXSelection::FromCurrentSelection(GetDocument());
EXPECT_FALSE(ax_selection.IsValid());
EXPECT_EQ("", GetSelectionText(ax_selection));
}
TEST_F(AccessibilitySelectionTest, ClearCurrentSelectionInTextarea) {
GetPage().GetSettings().SetScriptEnabled(true);
SetBodyInnerHTML(R"HTML(
<textarea id="textarea">
Inside
textarea
field.
</textarea>
)HTML");
ASSERT_FALSE(AXSelection::FromCurrentSelection(GetDocument()).IsValid());
Element* const script_element =
GetDocument().CreateRawElement(html_names::kScriptTag);
ASSERT_NE(nullptr, script_element);
script_element->setTextContent(R"SCRIPT(
let textarea = document.querySelector('textarea');
textarea.focus();
textarea.selectionStart = 0;
textarea.selectionEnd = textarea.textLength;
)SCRIPT");
GetDocument().body()->AppendChild(script_element);
UpdateAllLifecyclePhasesForTest();
SelectionInDOMTree selection = Selection().GetSelectionInDOMTree();
ASSERT_FALSE(selection.IsNone());
AXSelection::ClearCurrentSelection(GetDocument());
selection = Selection().GetSelectionInDOMTree();
EXPECT_TRUE(selection.IsNone());
const auto ax_selection = AXSelection::FromCurrentSelection(GetDocument());
EXPECT_FALSE(ax_selection.IsValid());
EXPECT_EQ("", GetSelectionText(ax_selection));
}
TEST_F(AccessibilitySelectionTest, ForwardSelectionInTextField) { TEST_F(AccessibilitySelectionTest, ForwardSelectionInTextField) {
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<input id="input" value="Inside text field."> <input id="input" value="Inside text field.">
......
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