#include "content/browser/renderer_host/input/touch_selection_controller_client_aura.h"
#include <memory>
#include "base/command_line.h"
#include "base/json/json_reader.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h"
#include "build/chromeos_buildflags.h"
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
#include "content/browser/renderer_host/render_widget_host_view_event_handler.h"
#include "content/browser/renderer_host/text_input_manager.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/hit_test_region_observer.h"
#include "content/public/test/synchronize_visual_properties_interceptor.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "third_party/blink/public/common/switches.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/pointer/touch_editing_controller.h"
#include "ui/base/ui_base_features.h"
#include "ui/display/display_switches.h"
#include "ui/events/event_sink.h"
#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/test/event_generator.h"
#include "ui/events/test/motion_event_test_utils.h"
#include "ui/touch_selection/touch_selection_controller_test_api.h"
#include "ui/touch_selection/touch_selection_metrics.h"
namespace content {
namespace {
constexpr int kCharacterWidth = …;
constexpr int kCharacterHeight = …;
bool JSONToPoint(const std::string& str, gfx::PointF* point) { … }
gfx::RectF ConvertRectFToChildCoords(RenderWidgetHostViewAura* parent,
RenderWidgetHostViewChildFrame* child,
const gfx::RectF& rect) { … }
gfx::Point ConvertPointFromView(
RenderWidgetHostViewAura* view,
const ui::test::EventGeneratorDelegate* generator_delegate,
const gfx::PointF& point_in_view) { … }
class TestTouchSelectionMenuRunner : public ui::TouchSelectionMenuRunner { … };
}
class TestTouchSelectionControllerClientAura
: public TouchSelectionControllerClientAura,
public TextInputManager::Observer { … };
class TouchSelectionControllerClientAuraTest : public ContentBrowserTest { … };
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
InitiallyInactive) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
LongPressSelection) { … }
class TouchSelectionControllerClientAuraSiteIsolationTest
: public TouchSelectionControllerClientAuraTest,
public testing::WithParamInterface<bool> { … };
INSTANTIATE_TEST_SUITE_P(…);
IN_PROC_BROWSER_TEST_P(TouchSelectionControllerClientAuraSiteIsolationTest,
BasicSelectionIsolatedIframe) { … }
IN_PROC_BROWSER_TEST_P(TouchSelectionControllerClientAuraSiteIsolationTest,
DISABLED_BasicSelectionIsolatedScrollMainframe) { … }
IN_PROC_BROWSER_TEST_P(TouchSelectionControllerClientAuraSiteIsolationTest,
SelectionHandlesIsolatedIframeMainViewResized) { … }
IN_PROC_BROWSER_TEST_P(TouchSelectionControllerClientAuraSiteIsolationTest,
TouchSelectionDeactivatedAfterReload) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
BasicInsertionFollowedByTapsOnHandle) { … }
#if BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
LongPressDragSelectionReadableText) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
InitSelectionController(false);
RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
gfx::NativeView native_view = rwhva->GetNativeView();
ui::test::EventGenerator generator(native_view->GetRootWindow());
gfx::Point point_in_readable_text = gfx::ToRoundedPoint(GetPointInText(2));
generator.delegate()->ConvertPointFromTarget(native_view,
&point_in_readable_text);
SelectWithLongPress(generator, point_in_readable_text);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(4 * kCharacterWidth, kCharacterHeight));
InitiateTouchSelectionDragging(generator);
DragAndWaitForSelectionUpdate(generator, 5 * kCharacterWidth, 0);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some text");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(9 * kCharacterWidth, kCharacterHeight));
DragAndWaitForSelectionUpdate(generator, -3 * kCharacterWidth, 0);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some t");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(6 * kCharacterWidth, kCharacterHeight));
}
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
LongPressDragSelectionEditableText) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
InitSelectionController(false);
RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
gfx::NativeView native_view = rwhva->GetNativeView();
ui::test::EventGenerator generator(native_view->GetRootWindow());
gfx::Point point_in_textfield = gfx::ToRoundedPoint(GetPointInTextfield(2));
generator.delegate()->ConvertPointFromTarget(native_view,
&point_in_textfield);
SelectWithLongPress(generator, point_in_textfield);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(4 * kCharacterWidth, kCharacterHeight));
InitiateTouchSelectionDragging(generator);
DragAndWaitForSelectionUpdate(generator, 9 * kCharacterWidth, 0);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some editable");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(13 * kCharacterWidth, kCharacterHeight));
DragAndWaitForSelectionUpdate(generator, -kCharacterWidth, 0);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some editabl");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(12 * kCharacterWidth, kCharacterHeight));
}
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
DoublePressDragSelection) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
InitSelectionController(false);
RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
gfx::NativeView native_view = rwhva->GetNativeView();
ui::test::EventGenerator generator(native_view->GetRootWindow());
gfx::Point point_in_textfield = gfx::ToRoundedPoint(GetPointInTextfield(2));
generator.delegate()->ConvertPointFromTarget(native_view,
&point_in_textfield);
SelectWithDoublePress(generator, point_in_textfield);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(4 * kCharacterWidth, kCharacterHeight));
InitiateTouchSelectionDragging(generator);
DragAndWaitForSelectionUpdate(generator, 9 * kCharacterWidth, 0);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some editable");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(13 * kCharacterWidth, kCharacterHeight));
DragAndWaitForSelectionUpdate(generator, -kCharacterWidth, 0);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some editabl");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(12 * kCharacterWidth, kCharacterHeight));
}
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
SelectionDraggingDirectionStrategy) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
InitSelectionController(false);
RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
gfx::NativeView native_view = rwhva->GetNativeView();
ui::test::EventGenerator generator(native_view->GetRootWindow());
gfx::Point point_in_textfield = gfx::ToRoundedPoint(GetPointInTextfield(2));
generator.delegate()->ConvertPointFromTarget(native_view,
&point_in_textfield);
SelectWithDoublePress(generator, point_in_textfield);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(4 * kCharacterWidth, kCharacterHeight));
InitiateTouchSelectionDragging(generator);
DragAndWaitForSelectionUpdate(generator, 6 * kCharacterWidth, 0);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some editable");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(13 * kCharacterWidth, kCharacterHeight));
DragAndWaitForSelectionUpdate(generator, -6 * kCharacterWidth, 0);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some ed");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(7 * kCharacterWidth, kCharacterHeight));
DragAndWaitForSelectionUpdate(generator, 5 * kCharacterWidth, 0);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some edit");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(9 * kCharacterWidth, kCharacterHeight));
DragAndWaitForSelectionUpdate(generator, 8 * kCharacterWidth, 0);
EXPECT_EQ(rwhva->GetSelectedText(), u"Some editable text");
EXPECT_EQ(rwhva->selection_controller()->GetRectBetweenBounds().size(),
gfx::SizeF(18 * kCharacterWidth, kCharacterHeight));
}
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
SelectionDraggingShowsMagnifier) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
InitSelectionController(false);
RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
gfx::NativeView native_view = rwhva->GetNativeView();
ui::test::EventGenerator generator(native_view->GetRootWindow());
gfx::Point point_in_textfield = gfx::ToRoundedPoint(GetPointInTextfield(2));
generator.delegate()->ConvertPointFromTarget(native_view,
&point_in_textfield);
SelectWithDoublePress(generator, point_in_textfield);
InitiateTouchSelectionDragging(generator);
selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLES_MOVED);
generator.MoveTouchBy(8 * kCharacterWidth, 0);
selection_controller_client()->Wait();
EXPECT_TRUE(selection_controller_client()->IsMagnifierVisible());
selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLE_DRAG_STOPPED);
generator.ReleaseTouch();
selection_controller_client()->Wait();
EXPECT_FALSE(selection_controller_client()->IsMagnifierVisible());
}
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, TapOnCaret) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
InitSelectionController(true);
RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
const gfx::NativeView native_view = rwhva->GetNativeView();
ui::test::EventGenerator generator(native_view->GetRootWindow());
selection_controller_client()->InitWaitForSelectionUpdate();
gfx::Point point = gfx::ToRoundedPoint(GetPointInTextfield(2));
generator.delegate()->ConvertPointFromTarget(native_view, &point);
generator.MoveMouseTo(point);
generator.PressLeftButton();
selection_controller_client()->Wait();
EXPECT_EQ(rwhva->selection_controller()->active_status(),
ui::TouchSelectionController::INACTIVE);
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
selection_controller_client()->InitWaitForSelectionEvent(
ui::INSERTION_HANDLE_SHOWN);
selection_controller_client()->InitWaitForHandleContextMenu();
generator.GestureTapAt(point);
selection_controller_client()->Wait();
selection_controller_client()->WaitForHandleContextMenu();
EXPECT_EQ(rwhva->selection_controller()->active_status(),
ui::TouchSelectionController::INSERTION_ACTIVE);
EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
generator.AdvanceClock(base::Milliseconds(1000));
selection_controller_client()->InitWaitForHandleContextMenu();
generator.GestureTapAt(point);
selection_controller_client()->WaitForHandleContextMenu();
EXPECT_EQ(rwhva->selection_controller()->active_status(),
ui::TouchSelectionController::INSERTION_ACTIVE);
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
}
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
HandleVisibilityAfterMouseEvent) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
InitSelectionController(true);
RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
const gfx::NativeView native_view = rwhva->GetNativeView();
ui::test::EventGenerator generator(native_view->GetRootWindow());
selection_controller_client()->InitWaitForSelectionEvent(
ui::INSERTION_HANDLE_SHOWN);
gfx::Point caret_location = gfx::ToRoundedPoint(GetPointInTextfield(2));
generator.delegate()->ConvertPointFromTarget(native_view, &caret_location);
generator.GestureTapAt(caret_location);
selection_controller_client()->Wait();
const gfx::RectF caret_bounds =
rwhva->selection_controller()->GetVisibleRectBetweenBounds();
EXPECT_NE(caret_bounds, gfx::RectF());
EXPECT_EQ(rwhva->selection_controller()->active_status(),
ui::TouchSelectionController::INSERTION_ACTIVE);
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
selection_controller_client()->InitWaitForSelectionEvent(
ui::INSERTION_HANDLE_CLEARED);
generator.SendMouseEnter();
generator.MoveMouseBy(100, 100);
selection_controller_client()->Wait();
EXPECT_EQ(rwhva->selection_controller()->GetVisibleRectBetweenBounds(),
gfx::RectF());
EXPECT_EQ(rwhva->selection_controller()->active_status(),
ui::TouchSelectionController::INACTIVE);
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
generator.AdvanceClock(base::Milliseconds(1000));
selection_controller_client()->InitWaitForSelectionEvent(
ui::INSERTION_HANDLE_SHOWN);
generator.GestureTapAt(caret_location);
selection_controller_client()->Wait();
EXPECT_EQ(rwhva->selection_controller()->GetVisibleRectBetweenBounds(),
caret_bounds);
EXPECT_EQ(rwhva->selection_controller()->active_status(),
ui::TouchSelectionController::INSERTION_ACTIVE);
EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
SelectionDraggingMetrics) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
base::HistogramTester histogram_tester;
InitSelectionController(false);
RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
gfx::NativeView native_view = rwhva->GetNativeView();
ui::test::EventGenerator generator(native_view->GetRootWindow());
gfx::Point point_in_textfield = gfx::ToRoundedPoint(GetPointInTextfield(2));
generator.delegate()->ConvertPointFromTarget(native_view,
&point_in_textfield);
SelectWithLongPress(generator, point_in_textfield);
InitiateTouchSelectionDragging(generator);
DragAndWaitForSelectionUpdate(generator, 9 * kCharacterWidth, 0);
generator.ReleaseTouch();
histogram_tester.ExpectBucketCount(ui::kTouchSelectionDragTypeHistogramName,
ui::TouchSelectionDragType::kLongPressDrag,
1);
histogram_tester.ExpectTotalCount(ui::kTouchSelectionDragTypeHistogramName,
1);
ui::TouchSelectionMenuRunner::GetInstance()->CloseMenu();
SelectWithDoublePress(generator, point_in_textfield);
InitiateTouchSelectionDragging(generator);
DragAndWaitForSelectionUpdate(generator, 10 * kCharacterWidth, 0);
generator.ReleaseTouch();
histogram_tester.ExpectBucketCount(
ui::kTouchSelectionDragTypeHistogramName,
ui::TouchSelectionDragType::kDoublePressDrag, 1);
histogram_tester.ExpectTotalCount(ui::kTouchSelectionDragTypeHistogramName,
2);
generator.PressAndReleaseKey(ui::VKEY_A);
histogram_tester.ExpectUniqueSample(
ui::kTouchSelectionSessionTouchDownCountHistogramName, 3, 1);
}
#endif
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
DISABLED_QuickMenuHiddenOnTouch) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, HiddenOnScroll) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
SwipeToMoveCursorMagnifier) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
SelectAllCommand) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
SelectWordCommand) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
SelectCommandsEmptyTextfield) { … }
class TouchSelectionControllerClientAuraScaleFactorTest
: public TouchSelectionControllerClientAuraTest { … };
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraScaleFactorTest,
SelectionHandleCoordinates) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraScaleFactorTest,
SelectionHandleCoordinatesAfterDrag) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraScaleFactorTest,
SelectionHandleDragShowsMenu) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraScaleFactorTest,
SelectionHandleDragShowsMagnifier) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraScaleFactorTest,
InsertionHandleCoordinates) { … }
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraScaleFactorTest,
InsertionHandleDragShowsMagnifier) { … }
}