Commit 8ac6530d authored by Christopher Grant's avatar Christopher Grant Committed by Commit Bot

VR: Let clicks reposition the cursor in text fields.

BUG=799189
R=ymalik

Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_vr;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I055bda2aef02a3278a090a6ebdd31a8769e8d4ce
Reviewed-on: https://chromium-review.googlesource.com/884372Reviewed-by: default avatarYash Malik <ymalik@chromium.org>
Commit-Queue: Christopher Grant <cjgrant@chromium.org>
Cr-Commit-Position: refs/heads/master@{#531971}
parent 72d7b437
......@@ -121,6 +121,13 @@ class TextTexture : public UiTexture {
SetAndDirty(&cursor_position_, position);
}
int GetCursorPositionFromPoint(const gfx::PointF& point) const {
DCHECK_EQ(lines().size(), 1u);
gfx::Point pixel_position(point.x() * GetDrawnSize().width(),
point.y() * GetDrawnSize().height());
return lines().front()->FindCursorPosition(pixel_position).caret_pos();
}
void SetShadowsEnabled(bool enabled) {
SetAndDirty(&shadows_enabled_, enabled);
}
......@@ -137,7 +144,7 @@ class TextTexture : public UiTexture {
// the texture is modified here.
void LayOutText();
const std::vector<std::unique_ptr<gfx::RenderText>>& lines() {
const std::vector<std::unique_ptr<gfx::RenderText>>& lines() const {
return lines_;
}
......@@ -223,6 +230,10 @@ gfx::RectF Text::GetCursorBounds() const {
bounds.height() * scale * kCursorWidthRatio, bounds.height() * scale);
}
int Text::GetCursorPositionFromPoint(const gfx::PointF& point) const {
return texture_->GetCursorPositionFromPoint(point);
}
void Text::SetShadowsEnabled(bool enabled) {
texture_->SetShadowsEnabled(enabled);
}
......
......@@ -100,6 +100,8 @@ class Text : public TexturedElement {
// texture size, relative to the upper-left corner of the element.
gfx::RectF GetCursorBounds() const;
int GetCursorPositionFromPoint(const gfx::PointF& point) const;
// This causes the text to become uniformly shadowed.
void SetShadowsEnabled(bool enabled);
......
......@@ -69,6 +69,18 @@ void TextInput::SetTextInputDelegate(TextInputDelegate* text_input_delegate) {
delegate_ = text_input_delegate;
}
void TextInput::OnButtonDown(const gfx::PointF& position) {
// Reposition the cursor based on click position.
int cursor_position = text_element_->GetCursorPositionFromPoint(position);
TextInputInfo info(text_info_);
info.selection_start = cursor_position;
info.selection_end = cursor_position;
if (text_info_ != info) {
UpdateInput(info);
ResetCursorBlinkCycle();
}
}
void TextInput::OnButtonUp(const gfx::PointF& position) {
RequestFocus();
}
......@@ -125,6 +137,8 @@ void TextInput::SetHintColor(SkColor color) {
void TextInput::UpdateInput(const TextInputInfo& info) {
if (text_info_ == info)
return;
DCHECK_EQ(info.selection_start, info.selection_end);
text_info_ = info;
if (delegate_ && focused_)
......@@ -161,9 +175,9 @@ void TextInput::LayOutChildren() {
}
bool TextInput::SetCursorBlinkState(const base::TimeTicks& time) {
base::TimeDelta delta = time - base::TimeTicks();
base::TimeDelta delta = time - cursor_blink_start_ticks_;
bool visible =
focused_ && delta.InMilliseconds() / kCursorBlinkHalfPeriodMs % 2;
focused_ && (delta.InMilliseconds() / kCursorBlinkHalfPeriodMs + 1) % 2;
if (cursor_visible_ == visible)
return false;
cursor_visible_ = visible;
......@@ -171,4 +185,8 @@ bool TextInput::SetCursorBlinkState(const base::TimeTicks& time) {
return true;
}
void TextInput::ResetCursorBlinkCycle() {
cursor_blink_start_ticks_ = base::TimeTicks::Now();
}
} // namespace vr
......@@ -33,6 +33,7 @@ class TextInput : public UiElement {
OnInputEditedCallback input_edit_callback);
~TextInput() override;
void OnButtonDown(const gfx::PointF& position) override;
void OnButtonUp(const gfx::PointF& position) override;
void OnFocusChanged(bool focused) override;
void OnInputEdited(const TextInputInfo& info) override;
......@@ -64,6 +65,7 @@ class TextInput : public UiElement {
private:
void LayOutChildren() final;
bool SetCursorBlinkState(const base::TimeTicks& time);
void ResetCursorBlinkCycle();
OnFocusChangedCallback focus_changed_callback_;
OnInputEditedCallback input_edit_callback_;
......@@ -72,6 +74,7 @@ class TextInput : public UiElement {
TextInputInfo text_info_;
bool focused_ = false;
bool cursor_visible_ = false;
base::TimeTicks cursor_blink_start_ticks_;
Text* hint_element_ = nullptr;
Text* text_element_ = nullptr;
......
......@@ -61,8 +61,16 @@ void TestKeyboardDelegate::Initialize(vr::SkiaSurfaceProvider* provider,
renderer_->Initialize(provider, renderer);
}
void TestKeyboardDelegate::UpdateInput(const vr::TextInputInfo& info) {
if (input_info_ == info)
return;
input_info_ = info;
ui_interface_->OnInputEdited(input_info_);
}
bool TestKeyboardDelegate::HandleInput(ui::Event* e) {
DCHECK(keyboard_interface_);
DCHECK(ui_interface_);
DCHECK(e->IsKeyEvent());
if (!editing_)
return false;
......@@ -72,13 +80,13 @@ bool TestKeyboardDelegate::HandleInput(ui::Event* e) {
case ui::VKEY_RETURN:
input_info_.text.clear();
input_info_.selection_start = input_info_.selection_end = 0;
keyboard_interface_->OnInputCommitted(input_info_);
ui_interface_->OnInputCommitted(input_info_);
break;
case ui::VKEY_BACK:
input_info_.text.pop_back();
input_info_.selection_start--;
input_info_.selection_end--;
keyboard_interface_->OnInputEdited(input_info_);
ui_interface_->OnInputEdited(input_info_);
break;
default:
std::string character;
......@@ -86,7 +94,7 @@ bool TestKeyboardDelegate::HandleInput(ui::Event* e) {
input_info_.text = input_info_.text.append(base::UTF8ToUTF16(character));
input_info_.selection_start++;
input_info_.selection_end++;
keyboard_interface_->OnInputEdited(input_info_);
ui_interface_->OnInputEdited(input_info_);
break;
}
// We want to continue handling this keypress if the Ctrl key is down so
......
......@@ -40,14 +40,14 @@ class TestKeyboardDelegate : public KeyboardDelegate {
void Initialize(SkiaSurfaceProvider* provider, UiElementRenderer* renderer);
void SetUiInterface(KeyboardUiInterface* keyboard) {
keyboard_interface_ = keyboard;
ui_interface_ = keyboard;
}
void UpdateInput(const vr::TextInputInfo& info) { input_info_ = info; }
void UpdateInput(const vr::TextInputInfo& info);
bool HandleInput(ui::Event* e);
private:
std::unique_ptr<TestKeyboardRenderer> renderer_;
KeyboardUiInterface* keyboard_interface_ = nullptr;
KeyboardUiInterface* ui_interface_ = nullptr;
gfx::Transform world_space_transform_;
bool editing_;
TextInputInfo input_info_;
......
......@@ -32,6 +32,10 @@ using ::testing::StrictMock;
namespace vr {
namespace {
constexpr float kFontHeightMeters = 0.050f;
}
class MockTextInputDelegate : public TextInputDelegate {
public:
MockTextInputDelegate() = default;
......@@ -165,8 +169,8 @@ TEST(TextInputTest, ControllerInteractionsSentToDelegate) {
TEST(TextInputTest, HintText) {
UiScene scene;
auto instance =
std::make_unique<TextInput>(10, TextInput::OnFocusChangedCallback(),
auto instance = std::make_unique<TextInput>(
kFontHeightMeters, TextInput::OnFocusChangedCallback(),
TextInput::OnInputEditedCallback());
instance->SetName(kOmniboxTextField);
instance->SetSize(1, 0);
......@@ -185,11 +189,11 @@ TEST(TextInputTest, HintText) {
EXPECT_EQ(element->get_hint_element()->GetTargetOpacity(), 0);
}
TEST(TextInputTest, Cursor) {
TEST(TextInputTest, CursorBlinking) {
UiScene scene;
auto instance =
std::make_unique<TextInput>(10, TextInput::OnFocusChangedCallback(),
auto instance = std::make_unique<TextInput>(
kFontHeightMeters, TextInput::OnFocusChangedCallback(),
TextInput::OnInputEditedCallback());
instance->SetName(kOmniboxTextField);
instance->SetSize(1, 0);
......@@ -214,22 +218,56 @@ TEST(TextInputTest, Cursor) {
toggled = true;
}
EXPECT_TRUE(toggled);
}
// TODO(cjgrant): Continue with the test cases below, when they're debugged.
#if 0
TextInputInfo info;
info.text = base::UTF8ToUTF16("text");
// TODO(cjgrant): Have this test, and others similar, check the actual position
// of the cursor element. To make this work, the OnBeginFrame logic needs to be
// updated to perform more of the measurement and layout steps in a test
// environment. As of now, much of this is skipped due to lack of a GL context.
TEST(TextInputTest, CursorPositionUpdatesOnKeyboardInput) {
auto element = std::make_unique<TextInput>(
kFontHeightMeters, TextInput::OnFocusChangedCallback(),
TextInput::OnInputEditedCallback());
// When the cursor position moves, the cursor element should move.
TextInputInfo info(base::UTF8ToUTF16("text"));
info.selection_start = 0;
info.selection_end = 0;
element->UpdateInput(info);
auto result = element->get_text_element()->LayOutTextForTest({512, 512});
auto position1 = element->get_text_element()->GetRawCursorBounds();
element->get_text_element()->LayOutTextForTest();
int x1 = element->get_text_element()->GetRawCursorBounds().x();
info.selection_start = 1;
info.selection_end = 1;
element->UpdateInput(info);
element->get_text_element()->LayOutTextForTest({512, 512});
auto position2 = element->get_text_element()->GetRawCursorBounds();
EXPECT_NE(position1, position2);
#endif
element->get_text_element()->LayOutTextForTest();
int x2 = element->get_text_element()->GetRawCursorBounds().x();
EXPECT_LT(x1, x2);
}
TEST(TextInputTest, CursorPositionUpdatesOnClicks) {
auto element = std::make_unique<TextInput>(
kFontHeightMeters, TextInput::OnFocusChangedCallback(),
TextInput::OnInputEditedCallback());
TextInputInfo info(base::UTF8ToUTF16("text"));
element->UpdateInput(info);
element->get_text_element()->LayOutTextForTest();
// Click on the left edge of the field.
element->OnButtonDown(gfx::PointF(0.0, 0.5));
element->OnButtonUp(gfx::PointF(0.0, 0.5));
element->get_text_element()->LayOutTextForTest();
auto x1 = element->get_text_element()->GetRawCursorBounds().x();
// Click on the right edge of the field.
element->OnButtonDown(gfx::PointF(1.0, 0.5));
element->OnButtonUp(gfx::PointF(1.0, 0.5));
element->get_text_element()->LayOutTextForTest();
auto x2 = element->get_text_element()->GetRawCursorBounds().x();
EXPECT_EQ(x1, 0);
EXPECT_GT(x2, 0);
}
} // namespace vr
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