Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Unified Diff: ui/base/ime/android/cursor_anchor_info_controller_unittest.cc

Issue 643193003: Support InputMethodManager#updateCursorAnchorInfo for Android 5.0 (C++ version) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Send ImeCompositionRangeChanged only when necessary Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/base/ime/android/cursor_anchor_info_controller_unittest.cc
diff --git a/ui/base/ime/android/cursor_anchor_info_controller_unittest.cc b/ui/base/ime/android/cursor_anchor_info_controller_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8a7477dfefbfef509202cff03ff29222143682b9
--- /dev/null
+++ b/ui/base/ime/android/cursor_anchor_info_controller_unittest.cc
@@ -0,0 +1,927 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/android/cursor_anchor_info_controller.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/tuple.h"
+#include "cc/output/compositor_frame_metadata.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/android/cursor_anchor_info_builder.h"
+#include "ui/base/ime/android/cursor_anchor_info_sender.h"
+
+namespace ui {
+namespace {
+
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+using ::testing::FloatLE;
+
+const uint32 kFlagHasVisibleRegion =
+ CursorAnchorInfoBuilder::kFlagHasVisibleRegion;
+const uint32 kFlagHasInvisibleRegion =
+ CursorAnchorInfoBuilder::kFlagHasInvisibleRegion;
+
+const uint32 kCursorUpdateModeImmediate =
+ CursorAnchorInfoController::kCursorUpdateModeImmediate;
+const uint32 kCursorUpdateModeMonitor =
+ CursorAnchorInfoController::kCursorUpdateModeMonitor;
+
+template <typename T>
+std::vector<T> Vec() {
+ return std::vector<T>();
+}
+
+template <typename T>
+std::vector<T> Vec(const T& param1) {
+ std::vector<T> result;
+ result.push_back(param1);
+ return result;
+}
+
+template <typename T>
+std::vector<T> Vec(const T& param1, const T& param2) {
+ std::vector<T> result;
+ result.push_back(param1);
+ result.push_back(param2);
+ return result;
+}
+
+template <typename T>
+std::vector<T> Vec(const T& param1, const T& param2, const T& param3) {
+ std::vector<T> result;
+ result.push_back(param1);
+ result.push_back(param2);
+ result.push_back(param3);
+ return result;
+}
+
+typedef Tuple<int, base::string16> SetComposingTextParams;
+typedef Tuple<int, gfx::RectF, uint32> AddCharacterBoundsParams;
+typedef Tuple<float, float, float, float, uint32>
+SetInsertionMarkerLocationParams;
+typedef Tuple<float, gfx::Vector2dF> SetScaleAndTranslateParams;
+typedef Tuple<gfx::Range> SetSelectionRangeParams;
+
+class CursorAnchorInfoBuilderMock final
+ : public CursorAnchorInfoBuilder {
+ public:
+
+ CursorAnchorInfoBuilderMock()
+ : build_count_(0),
+ reset_count_(0) {
+ }
+
+ ~CursorAnchorInfoBuilderMock() override {
+ }
+
+ void AddCharacterBounds(int index,
+ const gfx::RectF& rect,
+ uint32 flags) override {
+ add_character_bounds_call_log_.push_back(MakeTuple(index, rect, flags));
+ }
+
+ base::android::ScopedJavaLocalRef<jobject> Build() override {
+ ++build_count_;
+ return base::android::ScopedJavaLocalRef<jobject>();
+ }
+
+ void Reset() override {
+ ++reset_count_;
+ }
+
+ void SetComposingText(int composing_text_start,
+ base::StringPiece16 composing_text) override {
+ set_composing_text_call_log_.push_back(
+ MakeTuple(composing_text_start,
+ composing_text.as_string()));
+ }
+
+ void SetInsertionMarkerLocation(float horizontal_position,
+ float line_top,
+ float line_baseline,
+ float line_bottom,
+ uint32 flags) override {
+ set_insertion_marker_location_call_log_.push_back(MakeTuple(
+ horizontal_position, line_top, line_baseline, line_bottom, flags));
+ }
+
+ void SetScaleAndTranslate(float scale,
+ const gfx::Vector2dF& translate) override {
+ set_scale_and_translate_call_log_.push_back(MakeTuple(
+ scale, translate));
+ }
+
+ void SetSelectionRange(const gfx::Range& range) override {
+ set_selection_range_call_log_.push_back(MakeTuple(range));
+ }
+
+ size_t build_count() const {
+ return build_count_;
+ }
+
+ size_t reset_count() const {
+ return reset_count_;
+ }
+
+ const std::vector<SetComposingTextParams>&
+ set_composing_text_call_log() const {
+ return set_composing_text_call_log_;
+ }
+
+ const std::vector<SetInsertionMarkerLocationParams>&
+ set_insertion_marker_location_call_log() const {
+ return set_insertion_marker_location_call_log_;
+ }
+
+ const std::vector<SetScaleAndTranslateParams>&
+ set_scale_and_translate_call_log() const {
+ return set_scale_and_translate_call_log_;
+ }
+
+ const std::vector<AddCharacterBoundsParams>&
+ add_character_bounds_call_log() const {
+ return add_character_bounds_call_log_;
+ }
+
+ const std::vector<SetSelectionRangeParams>&
+ set_selection_range_call_log() const {
+ return set_selection_range_call_log_;
+ }
+
+ private:
+ size_t build_count_;
+ size_t reset_count_;
+ std::vector<SetComposingTextParams> set_composing_text_call_log_;
+ std::vector<SetInsertionMarkerLocationParams>
+ set_insertion_marker_location_call_log_;
+ std::vector<SetScaleAndTranslateParams> set_scale_and_translate_call_log_;
+ std::vector<AddCharacterBoundsParams> add_character_bounds_call_log_;
+ std::vector<SetSelectionRangeParams> set_selection_range_call_log_;
+
+ DISALLOW_COPY_AND_ASSIGN(CursorAnchorInfoBuilderMock);
+};
+
+class CursorAnchorInfoSenderMock final
+ : public CursorAnchorInfoSender {
+ public:
+
+ CursorAnchorInfoSenderMock()
+ : send_count_(0) {
+ }
+
+ ~CursorAnchorInfoSenderMock() override {
+ }
+
+ void SendCursorAnchorInfo(ui::CursorAnchorInfoBuilder* builder) override {
+ ++send_count_;
+ }
+
+ size_t send_count() const {
+ return send_count_;
+ }
+
+ private:
+ size_t send_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(CursorAnchorInfoSenderMock);
+};
+
+enum UpdateControllerType {
+ kCallOnTextInputStateChanged = 1 << 0,
+ kCallOnCompositionRangeChanged = 1 << 1,
+ kCallOnFrameMetadataUpdated = 1 << 2,
+};
+
+cc::ViewportSelectionBound CreateViewportSelectionBoundForTest(
+ cc::SelectionBoundType type,
+ const gfx::PointF& edge_top,
+ const gfx::PointF& edge_bottom,
+ bool visible) {
+ cc::ViewportSelectionBound selection_bound;
+ selection_bound.type = type;
+ selection_bound.edge_top = edge_top;
+ selection_bound.edge_bottom = edge_bottom;
+ selection_bound.visible = visible;
+ return selection_bound;
+}
+
+cc::CompositorFrameMetadata CreateFrameMetadataForTest(
+ float device_scale_factor,
+ const gfx::Vector2dF& root_scroll_offset,
+ float page_scale_factor,
+ const gfx::Vector2dF& location_bar_offset,
+ const gfx::Vector2dF& location_bar_content_translation,
+ const cc::ViewportSelectionBound& selection_start) {
+ cc::CompositorFrameMetadata frame_metadata;
+ frame_metadata.device_scale_factor = device_scale_factor;
+ frame_metadata.root_scroll_offset = root_scroll_offset;
+ frame_metadata.page_scale_factor = page_scale_factor;
+ frame_metadata.location_bar_offset = location_bar_offset;
+ frame_metadata.location_bar_content_translation =
+ location_bar_content_translation;
+ frame_metadata.selection_start = selection_start;
+ return frame_metadata;
+}
+
+void UpdateController(CursorAnchorInfoController* controller,
+ int update_type,
+ int salt) {
+ if ((update_type & kCallOnTextInputStateChanged) != 0) {
+ const base::string16 kDummyText = base::ASCIIToUTF16("0123456789");
+ const gfx::Range kDummySelectionRange(0, salt);
+ const gfx::Range kDummyCompositionRange(3, 5);
+ controller->OnTextInputStateChanged(kDummyText,
+ kDummySelectionRange,
+ kDummyCompositionRange);
+ }
+
+ if ((update_type & kCallOnCompositionRangeChanged) != 0) {
+ const gfx::Range kDummyRange(0, salt);
+ std::vector<gfx::Rect> dummyCompositionRects;
+ dummyCompositionRects.push_back(gfx::Rect(10, 3, 5, 8));
+ dummyCompositionRects.push_back(gfx::Rect(15, 3, 5, 8));
+ controller->OnCompositionRangeChanged(kDummyRange, dummyCompositionRects);
+ }
+
+ if ((update_type & kCallOnFrameMetadataUpdated) != 0) {
+ const auto selection_start = CreateViewportSelectionBoundForTest(
+ cc::SELECTION_BOUND_CENTER,
+ gfx::PointF(240.0f, 41.0f),
+ gfx::PointF(240.0f, 64.0f),
+ true);
+ const cc::CompositorFrameMetadata dummy_frame_metadata =
+ CreateFrameMetadataForTest(
+ 2.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ 1.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ gfx::Vector2dF(0.0f, 0.0f),
+ selection_start);
+ const gfx::Vector2d kDummyViewOriginOffset(0, salt);
+ controller->OnFrameMetadataUpdated(dummy_frame_metadata,
+ kDummyViewOriginOffset);
+ }
+}
+
+bool FloatAlmostEqual(float a, float b) {
+ return FloatLE("a", "b", a, b) && FloatLE("b", "a", b, a);
+}
+
+AssertionResult AssertSetInsertionMarkerLocation(
+ const std::vector<SetInsertionMarkerLocationParams>& expected_call_log,
+ const cc::ViewportSelectionBound& selection_start) {
+
+ CursorAnchorInfoSenderMock sender_mock;
+ // This object will be owned by |controller|.
+ CursorAnchorInfoBuilderMock* builder_mock = new CursorAnchorInfoBuilderMock;
+ auto controller = CursorAnchorInfoController::CreateForTest(
+ &sender_mock,
+ scoped_ptr<CursorAnchorInfoBuilder>(builder_mock));
+ // Mark as editable.
+ controller->OnFocusedNodeChanged(true);
+
+ // Enable monitor.
+ controller->OnRequestCursorUpdates(kCursorUpdateModeMonitor);
+
+ controller->OnFrameMetadataUpdated(
+ CreateFrameMetadataForTest(
+ 1.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ 1.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ gfx::Vector2dF(0.0f, 0.0f),
+ selection_start),
+ gfx::Vector2d(0, 0));
+
+ const auto& actual_call_log =
+ builder_mock->set_insertion_marker_location_call_log();
+ if (expected_call_log.size() != actual_call_log.size()) {
+ return AssertionFailure()
+ << "Call count of SetInsertionMarkerLocation is unexpected."
+ << "\nExpected call count: " << expected_call_log.size()
+ << "\n Actual call count: " << actual_call_log.size();
+ }
+
+ for (size_t i = 0; i < expected_call_log.size(); ++i) {
+ const auto& expected = expected_call_log[i];
+ const auto& actual = actual_call_log[i];
+ if (!FloatAlmostEqual(get<0>(expected), get<0>(actual))) {
+ return AssertionFailure()
+ << "SetInsertionMarkerLocation is called with an unexpected "
+ << "parameter."
+ << "\n parameter: horizontal_position"
+ << "\n expected: " << get<0>(expected)
+ << "\n actual: " << get<0>(actual);
+ }
+ if (!FloatAlmostEqual(get<1>(expected), get<1>(actual))) {
+ return AssertionFailure()
+ << "SetInsertionMarkerLocation is called with an unexpected "
+ << "parameter."
+ << "\n parameter: line_top"
+ << "\n expected: " << get<1>(expected)
+ << "\n actual: " << get<1>(actual);
+ }
+ if (!FloatAlmostEqual(get<2>(expected), get<2>(actual))) {
+ return AssertionFailure()
+ << "SetInsertionMarkerLocation is called with an unexpected "
+ << "parameter."
+ << "\n parameter: line_baseline"
+ << "\n expected: " << get<2>(expected)
+ << "\n actual: " << get<2>(actual);
+ }
+ if (!FloatAlmostEqual(get<3>(expected), get<3>(actual))) {
+ return AssertionFailure()
+ << "SetInsertionMarkerLocation is called with an unexpected parameter."
+ << "\n parameter: line_bottom"
+ << "\n expected: " << get<3>(expected)
+ << "\n actual: " << get<3>(actual);
+ }
+ if (get<4>(expected) != get<4>(actual)) {
+ return AssertionFailure()
+ << "SetInsertionMarkerLocation is called with an unexpected "
+ << "parameter."
+ << "\n parameter: flags"
+ << "\n expected: " << get<4>(expected)
+ << "\n actual: " << get<4>(actual);
+ }
+ }
+ return AssertionSuccess();
+}
+
+AssertionResult AssertSetScaleAndTranslate(
+ float expected_scale,
+ const gfx::Vector2dF& expected_translate,
+ const cc::CompositorFrameMetadata& frame_metadata,
+ const gfx::Vector2d& view_origin_offset) {
+ CursorAnchorInfoSenderMock sender_mock;
+ // This object will be owned by |controller|.
+ CursorAnchorInfoBuilderMock* builder_mock = new CursorAnchorInfoBuilderMock;
+ auto controller = CursorAnchorInfoController::CreateForTest(
+ &sender_mock,
+ scoped_ptr<CursorAnchorInfoBuilder>(builder_mock));
+
+ controller->OnFocusedNodeChanged(true);
+ controller->OnRequestCursorUpdates(kCursorUpdateModeMonitor);
+
+ controller->OnFrameMetadataUpdated(frame_metadata, view_origin_offset);
+
+ const auto& log = builder_mock->set_scale_and_translate_call_log();
+ if (log.size() != 1) {
+ return AssertionFailure()
+ << "SetScaleAndTranslate is not called just once. "
+ << "Actual call count: " << log.size();
+ }
+
+ const float actual_scale = get<0>(log[0]);
+ if (!FloatAlmostEqual(expected_scale, actual_scale)) {
+ return AssertionFailure()
+ << "SetScaleAndTranslate is called with an unexpected parameter."
+ << "\n parameter: scale"
+ << "\n expected: " << expected_scale
+ << "\n actual: " << get<0>(log[0]);
+ }
+
+ const auto& actual_translate = get<1>(log[0]);
+ if (!FloatAlmostEqual(expected_translate.x(), actual_translate.x()) ||
+ !FloatAlmostEqual(expected_translate.y(), actual_translate.y())) {
+ return AssertionFailure()
+ << "SetScaleAndTranslate is called with an unexpected parameter."
+ << "\n parameter: translate"
+ << "\n expected: " << expected_translate.ToString()
+ << "\n actual: " << actual_translate.ToString();
+ }
+
+ return AssertionSuccess();
+}
+
+AssertionResult AssertOnTextInputStateChanged(
+ const std::vector<SetSelectionRangeParams>&
+ expected_set_selection_range_call_log,
+ const std::vector<SetComposingTextParams>&
+ expected_set_composing_text_call_log,
+ const base::string16& actual_text,
+ const gfx::Range& actual_selection_range,
+ const gfx::Range& actual_composition_range) {
+ CursorAnchorInfoSenderMock sender_mock;
+ // This object will be owned by |controller|.
+ CursorAnchorInfoBuilderMock* builder_mock = new CursorAnchorInfoBuilderMock;
+ auto controller = CursorAnchorInfoController::CreateForTest(
+ &sender_mock,
+ scoped_ptr<CursorAnchorInfoBuilder>(builder_mock));
+
+ controller->OnFocusedNodeChanged(true);
+ controller->OnRequestCursorUpdates(kCursorUpdateModeMonitor);
+
+ controller->OnTextInputStateChanged(actual_text,
+ actual_selection_range,
+ actual_composition_range);
+ // Calling OnFrameMetadataUpdated is mandatory to build an object.
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, 0);
+
+ {
+ const auto& expected_call_log = expected_set_selection_range_call_log;
+ const auto& actual_call_log = builder_mock->set_selection_range_call_log();
+ if (expected_call_log.size() != actual_call_log.size()) {
+ return AssertionFailure()
+ << "Call count of SetSelectionRange is unexpected."
+ << "\nExpected call count: " << expected_call_log.size()
+ << "\n Actual call count: " << actual_call_log.size();
+ }
+
+ for (size_t i = 0; i < expected_call_log.size(); ++i) {
+ const auto& expected = expected_call_log[i];
+ const auto& actual = actual_call_log[i];
+ if (get<0>(expected) != get<0>(actual)) {
+ return AssertionFailure()
+ << "SetSelectionRange is called with an unexpected parameter."
+ << "\n parameter: range"
+ << "\n expected: " << get<0>(expected)
+ << "\n actual: " << get<0>(actual);
+ }
+ }
+ }
+
+ {
+ const auto& expected_call_log = expected_set_composing_text_call_log;
+ const auto& actual_call_log = builder_mock->set_composing_text_call_log();
+ if (expected_call_log.size() != actual_call_log.size()) {
+ return AssertionFailure()
+ << "Call count of SetComposingText is unexpected."
+ << "\nExpected call count: " << expected_call_log.size()
+ << "\n Actual call count: " << actual_call_log.size();
+ }
+
+ for (size_t i = 0; i < expected_call_log.size(); ++i) {
+ const auto& expected = expected_call_log[i];
+ const auto& actual = actual_call_log[i];
+ if (get<0>(expected) != get<0>(actual)) {
+ return AssertionFailure()
+ << "SetComposingText is called with an unexpected parameter."
+ << "\n parameter: range"
+ << "\n expected: " << get<0>(expected)
+ << "\n actual: " << get<0>(actual);
+ }
+ if (get<1>(expected) != get<1>(actual)) {
+ return AssertionFailure()
+ << "SetComposingText is called with an unexpected parameter."
+ << "\n parameter: range"
+ << "\n expected: " << get<1>(expected)
+ << "\n actual: " << get<1>(actual);
+ }
+ }
+ }
+
+ return AssertionSuccess();
+}
+
+AssertionResult AssertOnCompositionRangeChanged(
+ const std::vector<AddCharacterBoundsParams>& expected_call_log,
+ const gfx::Range& actual_range,
+ const std::vector<gfx::Rect>& actual_character_bounds) {
+
+ CursorAnchorInfoSenderMock sender_mock;
+ // This object will be owned by |controller|.
+ CursorAnchorInfoBuilderMock* builder_mock = new CursorAnchorInfoBuilderMock;
+ auto controller = CursorAnchorInfoController::CreateForTest(
+ &sender_mock,
+ scoped_ptr<CursorAnchorInfoBuilder>(builder_mock));
+
+ controller->OnFocusedNodeChanged(true);
+ controller->OnRequestCursorUpdates(kCursorUpdateModeMonitor);
+
+ controller->OnCompositionRangeChanged(actual_range, actual_character_bounds);
+
+ // Calling OnFrameMetadataUpdated is mandatory to build an object.
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, 0);
+
+ {
+ const auto& actual_call_log = builder_mock->add_character_bounds_call_log();
+ if (expected_call_log.size() != actual_call_log.size()) {
+ return AssertionFailure()
+ << "Call count of AddCharacterBounds is unexpected."
+ << "\nExpected call count: " << expected_call_log.size()
+ << "\n Actual call count: " << actual_call_log.size();
+ }
+
+ for (size_t i = 0; i < expected_call_log.size(); ++i) {
+ const auto& expected = expected_call_log[i];
+ const auto& actual = actual_call_log[i];
+ if (get<0>(expected) != get<0>(actual)) {
+ return AssertionFailure()
+ << "AddCharacterBounds is called with an unexpected parameter."
+ << "\n parameter: index"
+ << "\n expected: " << get<0>(expected)
+ << "\n actual: " << get<0>(actual);
+ }
+ if (get<1>(expected) != get<1>(actual)) {
+ return AssertionFailure()
+ << "AddCharacterBounds is called with an unexpected parameter."
+ << "\n parameter: rect"
+ << "\n expected: " << get<1>(expected).ToString()
+ << "\n actual: " << get<1>(actual).ToString();
+ }
+ if (get<2>(expected) != get<2>(actual)) {
+ return AssertionFailure()
+ << "AddCharacterBounds is called with an unexpected parameter."
+ << "\n parameter: flags"
+ << "\n expected: " << get<2>(expected)
+ << "\n actual: " << get<2>(actual);
+ }
+ }
+
+ }
+
+ return AssertionSuccess();
+}
+
+/////////////////////////////////////////////////////
+
+TEST(CursorAnchorInfoControllerTest, OnFocusedNodeChanged) {
+ CursorAnchorInfoSenderMock sender_mock;
+ // This object will be owned by |controller|.
+ CursorAnchorInfoBuilderMock* builder_mock = new CursorAnchorInfoBuilderMock;
+ auto controller = CursorAnchorInfoController::CreateForTest(
+ &sender_mock,
+ scoped_ptr<CursorAnchorInfoBuilder>(builder_mock));
+
+ // Check the initial state.
+ ASSERT_EQ(0u, sender_mock.send_count());
+
+ ASSERT_TRUE(controller->OnRequestCursorUpdates(kCursorUpdateModeMonitor));
+
+ int salt = 0;
+ ASSERT_EQ(0u, sender_mock.send_count())
+ << "Data must not be sent when the node is not editable.";
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, salt);
+ ASSERT_EQ(0u, sender_mock.send_count())
+ << "Data must not be sent when the node is not editable.";
+
+ controller->OnFocusedNodeChanged(true);
+
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, salt);
+ ASSERT_EQ(1u, sender_mock.send_count())
+ << "Data can be sent when the node is editable.";
+
+ controller->OnFocusedNodeChanged(false);
+ ASSERT_TRUE(controller->OnRequestCursorUpdates(kCursorUpdateModeMonitor));
+
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, salt);
+ ASSERT_EQ(1u, sender_mock.send_count())
+ << "Data must not be sent when the node is not editable.";
+
+ controller->OnFocusedNodeChanged(true);
+ ASSERT_TRUE(controller->OnRequestCursorUpdates(kCursorUpdateModeMonitor));
+
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, salt);
+ ASSERT_EQ(2u, sender_mock.send_count()) <<
+ "Data must be sent even with the same data (derived from the same salt)"
+ " because OnFocusedNodeChanged resets internal state.";
+}
+
+TEST(CursorAnchorInfoControllerTest, CursorUpdateModeImmediate) {
+ CursorAnchorInfoSenderMock sender_mock;
+ // This object will be owned by |controller|.
+ CursorAnchorInfoBuilderMock* builder_mock = new CursorAnchorInfoBuilderMock;
+ auto controller = CursorAnchorInfoController::CreateForTest(
+ &sender_mock,
+ scoped_ptr<CursorAnchorInfoBuilder>(builder_mock));
+ controller->OnFocusedNodeChanged(true);
+
+ // Check the initial state.
+ ASSERT_EQ(0u, sender_mock.send_count());
+
+ int salt = 0;
+
+ ASSERT_TRUE(controller->OnRequestCursorUpdates(kCursorUpdateModeImmediate));
+ ASSERT_EQ(0u, sender_mock.send_count())
+ << "Data must not be sent except for |OnFrameMetadataUpdated|.";
+ ++salt;
+ UpdateController(controller.get(), kCallOnTextInputStateChanged, salt);
+ ASSERT_EQ(0u, sender_mock.send_count())
+ << "Data must not be sent except for |OnFrameMetadataUpdated|.";
+ ++salt;
+ UpdateController(controller.get(), kCallOnCompositionRangeChanged, salt);
+ ASSERT_EQ(0u, sender_mock.send_count())
+ << "Data must not be sent except for |OnFrameMetadataUpdated|.";
+ ++salt;
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, salt);
+ ASSERT_EQ(1u, sender_mock.send_count())
+ << "Data must be sent from |OnFrameMetadataUpdated| when requested.";
+
+ ++salt;
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, salt);
+ ASSERT_EQ(1u, sender_mock.send_count())
+ << "Don't need to send data twice in the immediate mode.";
+}
+
+TEST(CursorAnchorInfoControllerTest, CursorUpdateModeMonitor) {
+ CursorAnchorInfoSenderMock sender_mock;
+ // This object will be owned by |controller|.
+ CursorAnchorInfoBuilderMock* builder_mock = new CursorAnchorInfoBuilderMock;
+ auto controller = CursorAnchorInfoController::CreateForTest(
+ &sender_mock,
+ scoped_ptr<CursorAnchorInfoBuilder>(builder_mock));
+ controller->OnFocusedNodeChanged(true);
+
+ // Check the initial state.
+ ASSERT_EQ(0u, sender_mock.send_count());
+
+ int frame_metadata_salt = 0;
+ int salt = 0;
+
+ // Test monitor mode:
+ ASSERT_TRUE(controller->OnRequestCursorUpdates(kCursorUpdateModeMonitor));
+ ASSERT_EQ(0u, sender_mock.send_count());
+
+ ++salt;
+ UpdateController(controller.get(), kCallOnTextInputStateChanged, salt);
+ ASSERT_EQ(0u, sender_mock.send_count())
+ << "Data must not be sent except for |OnFrameMetadataUpdated|.";
+ ++salt;
+ UpdateController(controller.get(), kCallOnCompositionRangeChanged, salt);
+ ASSERT_EQ(0u, sender_mock.send_count())
+ << "Data must not be sent except for |OnFrameMetadataUpdated|.";
+ ++salt;
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, salt);
+ ASSERT_EQ(1u, sender_mock.send_count())
+ << "Data must be sent from |OnFrameMetadataUpdated| when requested.";
+ frame_metadata_salt = salt;
+
+ UpdateController(controller.get(),
+ kCallOnFrameMetadataUpdated,
+ frame_metadata_salt);
+ ASSERT_EQ(1u, sender_mock.send_count())
+ << "Data must not be sent because no data is changed.";
+
+ ++salt;
+ UpdateController(controller.get(), kCallOnTextInputStateChanged, salt);
+ ASSERT_EQ(1u, sender_mock.send_count())
+ << "Data must not be sent except for |OnFrameMetadataUpdated|.";
+ UpdateController(controller.get(),
+ kCallOnFrameMetadataUpdated,
+ frame_metadata_salt);
+ ASSERT_EQ(2u, sender_mock.send_count())
+ << "Data must be sent because |OnTextInputStateChanged| changed data.";
+ UpdateController(controller.get(), kCallOnTextInputStateChanged, salt);
+ ASSERT_EQ(2u, sender_mock.send_count())
+ << "Data must not be sent except for |OnFrameMetadataUpdated|.";
+ UpdateController(controller.get(),
+ kCallOnFrameMetadataUpdated,
+ frame_metadata_salt);
+ ASSERT_EQ(2u, sender_mock.send_count())
+ << "Data must not be sent because no data is changed.";
+
+ ++salt;
+ UpdateController(controller.get(), kCallOnCompositionRangeChanged, salt);
+ ASSERT_EQ(2u, sender_mock.send_count())
+ << "Data must not be sent except for |OnFrameMetadataUpdated|.";
+ UpdateController(controller.get(),
+ kCallOnFrameMetadataUpdated,
+ frame_metadata_salt);
+ ASSERT_EQ(3u, sender_mock.send_count())
+ << "Data must be sent because |OnCompositionRangeChanged| changed data.";
+ UpdateController(controller.get(), kCallOnCompositionRangeChanged, salt);
+ UpdateController(controller.get(),
+ kCallOnFrameMetadataUpdated,
+ frame_metadata_salt);
+ ASSERT_EQ(3u, sender_mock.send_count())
+ << "Data must not be sent because no data is changed.";
+
+ // Test if we can turn off the monitor mode.
+ ASSERT_TRUE(controller->OnRequestCursorUpdates(0));
+
+ ++salt;
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, salt);
+ ASSERT_EQ(3u, sender_mock.send_count())
+ << "Data must not be sent because the monitor mode is turned off.";
+
+ // Test if we can turn on the monitor mode and immediate mode at the same
+ // time.
+ ASSERT_TRUE(controller->OnRequestCursorUpdates(
+ kCursorUpdateModeMonitor | kCursorUpdateModeImmediate));
+ ASSERT_EQ(4u, sender_mock.send_count())
+ << "Data must be sent because the immediate mode is requested.";
+
+ ++salt;
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, salt);
+ ASSERT_EQ(5u, sender_mock.send_count())
+ << "Data must be sent from |OnFrameMetadataUpdated| when requested.";
+
+
+ // Test if |OnFocusedNodeChanged(true)| resets the monitor mode.
+ controller->OnFocusedNodeChanged(true);
+
+ ++salt;
+ UpdateController(controller.get(), kCallOnFrameMetadataUpdated, salt);
+ ASSERT_EQ(6u, sender_mock.send_count())
+ << "Data must be sent because |Reset| doesn't reset the monitor "
+ << "mode";
+
+}
+
+TEST(CursorAnchorInfoControllerTest, SetInsertionMarkerLocation) {
+ // Case 1: The insertion marker is visible
+ EXPECT_TRUE(AssertSetInsertionMarkerLocation(
+ Vec(MakeTuple(3.0f, 4.0f, 14.0f, 14.0f, kFlagHasVisibleRegion)),
+ CreateViewportSelectionBoundForTest(
+ cc::SELECTION_BOUND_CENTER,
+ gfx::PointF(3.0f, 4.0f),
+ gfx::PointF(3.0f, 14.0f),
+ true)));
+
+ // Case 2: The insertion marker is invisible
+ EXPECT_TRUE(AssertSetInsertionMarkerLocation(
+ Vec(MakeTuple(3.0f, 4.0f, 14.0f, 14.0f, kFlagHasInvisibleRegion)),
+ CreateViewportSelectionBoundForTest(
+ cc::SELECTION_BOUND_CENTER,
+ gfx::PointF(3.0f, 4.0f),
+ gfx::PointF(3.0f, 14.0f),
+ false)));
+
+ // Case 3: No insertion marker
+ EXPECT_TRUE(AssertSetInsertionMarkerLocation(
+ Vec<SetInsertionMarkerLocationParams>(),
+ CreateViewportSelectionBoundForTest(
+ cc::SELECTION_BOUND_EMPTY,
+ gfx::PointF(0.0f, 0.0f),
+ gfx::PointF(0.0f, 0.0f),
+ false)));
+}
+
+TEST(CursorAnchorInfoControllerTest, SetScaleAndTranslate) {
+ const auto empty_selection_start = CreateViewportSelectionBoundForTest(
+ cc::SELECTION_BOUND_EMPTY,
+ gfx::PointF(0.0f, 0.0f),
+ gfx::PointF(0.0f, 0.0f),
+ false);
+
+ // No transformation
+ EXPECT_TRUE(AssertSetScaleAndTranslate(
+ 1.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ CreateFrameMetadataForTest(
+ 1.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ 1.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ gfx::Vector2dF(0.0f, 0.0f),
+ empty_selection_start),
+ gfx::Vector2d(0, 0)));
+
+ // device_scale_factor == 2.0
+ EXPECT_TRUE(AssertSetScaleAndTranslate(
+ 2.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ CreateFrameMetadataForTest(
+ 2.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ 1.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ gfx::Vector2dF(0.0f, 0.0f),
+ empty_selection_start),
+ gfx::Vector2d(0, 0)));
+
+ // device_scale_factor == 2.0f
+ // view_origin_offset == (10, 141)
+ EXPECT_TRUE(AssertSetScaleAndTranslate(
+ 2.0f,
+ gfx::Vector2dF(10.0f, 141.0f),
+ CreateFrameMetadataForTest(
+ 2.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ 1.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ gfx::Vector2dF(0.0f, 0.0f),
+ empty_selection_start),
+ gfx::Vector2d(10, 141)));
+
+ // device_scale_factor == 2.0f
+ // root_scroll_offset == (1.0f, 2.0f)
+ // view_origin_offset == (10.0f, 141.0f)
+ EXPECT_TRUE(AssertSetScaleAndTranslate(
+ 2.0f,
+ gfx::Vector2dF(10.0f - 2.0f, 141.0f - 4.0f),
+ CreateFrameMetadataForTest(
+ 2.0f,
+ gfx::Vector2dF(1.0f, 2.0f),
+ 1.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ gfx::Vector2dF(0.0f, 0.0f),
+ empty_selection_start),
+ gfx::Vector2d(10, 141)));
+
+ // device_scale_factor == 2.0f
+ // page_scale_factor == 3.0f
+ // root_scroll_offset == (1.0f, 2.0f)
+ // view_origin_offset == (10.0f, 141.0f)
+ EXPECT_TRUE(AssertSetScaleAndTranslate(
+ 6.0f,
+ gfx::Vector2dF(10.0f - 6.0f, 141.0f - 12.0f),
+ CreateFrameMetadataForTest(
+ 2.0f,
+ gfx::Vector2dF(1.0f, 2.0f),
+ 3.0f,
+ gfx::Vector2dF(0.0f, 0.0f),
+ gfx::Vector2dF(0.0f, 0.0f),
+ empty_selection_start),
+ gfx::Vector2d(10, 141)));
+
+ // device_scale_factor == 2.0f
+ // page_scale_factor == 3.0f
+ // root_scroll_offset == (1.0f, 2.0f)
+ // location_bar_offset == (20.0f, 30.0f)
+ // view_origin_offset == (10.0f, 141.0f)
+ EXPECT_TRUE(AssertSetScaleAndTranslate(
+ 6.0f,
+ gfx::Vector2dF(30.0f - 6.0f, 171.0f - 12.0f),
+ CreateFrameMetadataForTest(
+ 2.0f,
+ gfx::Vector2dF(1.0f, 2.0f),
+ 3.0f,
+ gfx::Vector2dF(20.0f, 30.0f),
+ gfx::Vector2dF(0.0f, 0.0f),
+ empty_selection_start),
+ gfx::Vector2d(10, 141)));
+
+ // device_scale_factor == 2.0f
+ // page_scale_factor == 3.0f
+ // root_scroll_offset == (1.0f, 2.0f)
+ // location_bar_offset == (10.0f, 20.0f)
+ // location_bar_content_translation == (30.0f, 40.0f)
+ // view_origin_offset == (10.0f, 141.0f)
+ EXPECT_TRUE(AssertSetScaleAndTranslate(
+ 6.0f,
+ gfx::Vector2dF(70.0f - 6.0f, 221.0f - 12.0f),
+ CreateFrameMetadataForTest(
+ 2.0f,
+ gfx::Vector2dF(1.0f, 2.0f),
+ 3.0f,
+ gfx::Vector2dF(20.0f, 30.0f),
+ gfx::Vector2dF(40.0f, 50.0f),
+ empty_selection_start),
+ gfx::Vector2d(10, 141)));
+}
+
+TEST(CursorAnchorInfoControllerTest, OnTextInputStateChanged) {
+ EXPECT_TRUE(AssertOnTextInputStateChanged(
+ Vec(MakeTuple(gfx::Range(1, 9))),
+ Vec(MakeTuple(3, base::ASCIIToUTF16("34"))),
+ base::ASCIIToUTF16("0123456789"),
+ gfx::Range(1, 9),
+ gfx::Range(3, 5)));
+
+ // Test if the composing range is out of range.
+ EXPECT_TRUE(AssertOnTextInputStateChanged(
+ Vec(MakeTuple(gfx::Range(1, 9))),
+ Vec(MakeTuple(100, base::ASCIIToUTF16(""))),
+ base::ASCIIToUTF16("0123456789"),
+ gfx::Range(1, 9),
+ gfx::Range(100, 0)));
+
+ // Test if the composing range is out of range.
+ EXPECT_TRUE(AssertOnTextInputStateChanged(
+ Vec(MakeTuple(gfx::Range(1, 9))),
+ Vec(MakeTuple(-1, base::ASCIIToUTF16(""))),
+ base::ASCIIToUTF16(""),
+ gfx::Range(1, 9),
+ gfx::Range(-1, 1)));
+}
+
+TEST(CursorAnchorInfoControllerTest, OnCompositionRangeChanged) {
+ EXPECT_TRUE(AssertOnCompositionRangeChanged(
+ Vec<AddCharacterBoundsParams>(),
+ gfx::Range(0, 0),
+ Vec<gfx::Rect>()));
+
+ EXPECT_TRUE(AssertOnCompositionRangeChanged(
+ Vec(MakeTuple(1,
+ gfx::RectF(1.0f, 2.0f, 3.0f, 4.0f),
+ kFlagHasVisibleRegion),
+ MakeTuple(2,
+ gfx::RectF(5.0f, 6.0f, 7.0f, 8.0f),
+ kFlagHasVisibleRegion)),
+ gfx::Range(1, 3),
+ Vec(gfx::Rect(1, 2, 3, 4),
+ gfx::Rect(5, 6, 7, 8))));
+
+ EXPECT_TRUE(AssertOnCompositionRangeChanged(
+ Vec(MakeTuple(5,
+ gfx::RectF(1.0f, 2.0f, 3.0f, 4.0f),
+ kFlagHasVisibleRegion),
+ MakeTuple(6,
+ gfx::RectF(5.0f, 6.0f, 7.0f, 8.0f),
+ kFlagHasVisibleRegion),
+ MakeTuple(7,
+ gfx::RectF(9.0f, 10.0f, 11.0f, 12.0f),
+ kFlagHasVisibleRegion)),
+ gfx::Range(5, 8),
+ Vec(gfx::Rect(1, 2, 3, 4),
+ gfx::Rect(5, 6, 7, 8),
+ gfx::Rect(9, 10, 11, 12))));
+}
+
+} // namespace
+} // namespace ui
« no previous file with comments | « ui/base/ime/android/cursor_anchor_info_controller.cc ('k') | ui/base/ime/android/cursor_anchor_info_sender.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698