danakj | b009206 | 2020-05-04 19:53:06 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors. All rights reserved. |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
danakj | 89f4708 | 2020-09-02 17:53:43 | [diff] [blame] | 5 | #include "content/web_test/renderer/text_input_controller.h" |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 6 | |
avi | 5dd91f8 | 2015-12-25 22:30:46 | [diff] [blame] | 7 | #include "base/macros.h" |
Dave Tapuska | 13da016a | 2021-02-04 21:51:58 | [diff] [blame] | 8 | #include "content/web_test/renderer/web_frame_test_proxy.h" |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 9 | #include "gin/arguments.h" |
| 10 | #include "gin/handle.h" |
| 11 | #include "gin/object_template_builder.h" |
| 12 | #include "gin/wrappable.h" |
Dave Tapuska | 0dd120b | 2020-05-08 17:06:52 | [diff] [blame] | 13 | #include "third_party/blink/public/common/input/web_coalesced_input_event.h" |
Dave Tapuska | 129cef8 | 2019-12-19 16:36:48 | [diff] [blame] | 14 | #include "third_party/blink/public/common/input/web_keyboard_event.h" |
Blink Reformat | a30d423 | 2018-04-07 15:31:06 | [diff] [blame] | 15 | #include "third_party/blink/public/platform/web_input_event_result.h" |
Blink Reformat | a30d423 | 2018-04-07 15:31:06 | [diff] [blame] | 16 | #include "third_party/blink/public/web/blink.h" |
| 17 | #include "third_party/blink/public/web/web_frame_widget.h" |
Blink Reformat | a30d423 | 2018-04-07 15:31:06 | [diff] [blame] | 18 | #include "third_party/blink/public/web/web_input_method_controller.h" |
| 19 | #include "third_party/blink/public/web/web_local_frame.h" |
| 20 | #include "third_party/blink/public/web/web_range.h" |
| 21 | #include "third_party/blink/public/web/web_view.h" |
changwan | 9bdc18f0 | 2015-11-20 02:43:52 | [diff] [blame] | 22 | #include "third_party/skia/include/core/SkColor.h" |
Dave Tapuska | 7fa7521 | 2020-06-04 17:46:11 | [diff] [blame] | 23 | #include "ui/base/ime/ime_text_span.h" |
dtapuska | 899ac22 | 2017-01-03 18:09:16 | [diff] [blame] | 24 | #include "ui/events/base_event_utils.h" |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 25 | #include "v8/include/v8.h" |
| 26 | |
danakj | 741848a | 2020-04-07 22:48:06 | [diff] [blame] | 27 | namespace content { |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 28 | |
| 29 | class TextInputControllerBindings |
| 30 | : public gin::Wrappable<TextInputControllerBindings> { |
| 31 | public: |
| 32 | static gin::WrapperInfo kWrapperInfo; |
| 33 | |
Peter Boström | 9b03653 | 2021-10-28 23:37:28 | [diff] [blame^] | 34 | TextInputControllerBindings(const TextInputControllerBindings&) = delete; |
| 35 | TextInputControllerBindings& operator=(const TextInputControllerBindings&) = |
| 36 | delete; |
| 37 | |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 38 | static void Install(base::WeakPtr<TextInputController> controller, |
lukasza | 8b6d5f3 | 2016-04-22 16:56:31 | [diff] [blame] | 39 | blink::WebLocalFrame* frame); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 40 | |
| 41 | private: |
| 42 | explicit TextInputControllerBindings( |
| 43 | base::WeakPtr<TextInputController> controller); |
dcheng | e933b3e | 2014-10-21 11:44:09 | [diff] [blame] | 44 | ~TextInputControllerBindings() override; |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 45 | |
| 46 | // gin::Wrappable: |
dcheng | e933b3e | 2014-10-21 11:44:09 | [diff] [blame] | 47 | gin::ObjectTemplateBuilder GetObjectTemplateBuilder( |
anand.ratn | 449f39a4 | 2014-10-06 13:45:57 | [diff] [blame] | 48 | v8::Isolate* isolate) override; |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 49 | |
| 50 | void InsertText(const std::string& text); |
| 51 | void UnmarkText(); |
Ryan Landay | 7b5dbd5 | 2018-01-11 19:05:59 | [diff] [blame] | 52 | void UnmarkAndUnselectText(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 53 | void DoCommand(const std::string& text); |
Ryan Landay | 9c680942 | 2018-01-17 07:04:15 | [diff] [blame] | 54 | void ExtendSelectionAndDelete(int before, int after); |
Ryan Landay | 6d163ae | 2018-01-17 06:58:06 | [diff] [blame] | 55 | void DeleteSurroundingText(int before, int after); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 56 | void SetMarkedText(const std::string& text, int start, int length); |
Ryan Landay | d203467 | 2018-01-12 22:22:32 | [diff] [blame] | 57 | void SetMarkedTextFromExistingText(int start, int length); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 58 | bool HasMarkedText(); |
| 59 | std::vector<int> MarkedRange(); |
| 60 | std::vector<int> SelectedRange(); |
| 61 | std::vector<int> FirstRectForCharacterRange(unsigned location, |
| 62 | unsigned length); |
| 63 | void SetComposition(const std::string& text); |
ekaramad | 2daaf67 | 2016-11-10 20:29:01 | [diff] [blame] | 64 | void ForceTextInputStateUpdate(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 65 | |
| 66 | base::WeakPtr<TextInputController> controller_; |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 67 | }; |
| 68 | |
| 69 | gin::WrapperInfo TextInputControllerBindings::kWrapperInfo = { |
| 70 | gin::kEmbedderNativeGin}; |
| 71 | |
| 72 | // static |
| 73 | void TextInputControllerBindings::Install( |
| 74 | base::WeakPtr<TextInputController> controller, |
lukasza | 8b6d5f3 | 2016-04-22 16:56:31 | [diff] [blame] | 75 | blink::WebLocalFrame* frame) { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 76 | v8::Isolate* isolate = blink::MainThreadIsolate(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 77 | v8::HandleScope handle_scope(isolate); |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 78 | v8::Local<v8::Context> context = frame->MainWorldScriptContext(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 79 | if (context.IsEmpty()) |
| 80 | return; |
| 81 | |
| 82 | v8::Context::Scope context_scope(context); |
| 83 | |
| 84 | gin::Handle<TextInputControllerBindings> bindings = |
| 85 | gin::CreateHandle(isolate, new TextInputControllerBindings(controller)); |
[email protected] | ad4d203 | 2014-04-28 13:50:59 | [diff] [blame] | 86 | if (bindings.IsEmpty()) |
| 87 | return; |
deepak.s | 750d68f | 2015-04-30 07:32:41 | [diff] [blame] | 88 | v8::Local<v8::Object> global = context->Global(); |
Dan Elphick | a83be51 | 2019-02-05 15:57:23 | [diff] [blame] | 89 | global |
| 90 | ->Set(context, gin::StringToV8(isolate, "textInputController"), |
| 91 | bindings.ToV8()) |
| 92 | .Check(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 93 | } |
| 94 | |
| 95 | TextInputControllerBindings::TextInputControllerBindings( |
| 96 | base::WeakPtr<TextInputController> controller) |
| 97 | : controller_(controller) {} |
| 98 | |
| 99 | TextInputControllerBindings::~TextInputControllerBindings() {} |
| 100 | |
| 101 | gin::ObjectTemplateBuilder |
| 102 | TextInputControllerBindings::GetObjectTemplateBuilder(v8::Isolate* isolate) { |
| 103 | return gin::Wrappable<TextInputControllerBindings>::GetObjectTemplateBuilder( |
| 104 | isolate) |
| 105 | .SetMethod("insertText", &TextInputControllerBindings::InsertText) |
| 106 | .SetMethod("unmarkText", &TextInputControllerBindings::UnmarkText) |
Ryan Landay | 7b5dbd5 | 2018-01-11 19:05:59 | [diff] [blame] | 107 | .SetMethod("unmarkAndUnselectText", |
| 108 | &TextInputControllerBindings::UnmarkAndUnselectText) |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 109 | .SetMethod("doCommand", &TextInputControllerBindings::DoCommand) |
Ryan Landay | 9c680942 | 2018-01-17 07:04:15 | [diff] [blame] | 110 | .SetMethod("extendSelectionAndDelete", |
| 111 | &TextInputControllerBindings::ExtendSelectionAndDelete) |
Ryan Landay | 6d163ae | 2018-01-17 06:58:06 | [diff] [blame] | 112 | .SetMethod("deleteSurroundingText", |
| 113 | &TextInputControllerBindings::DeleteSurroundingText) |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 114 | .SetMethod("setMarkedText", &TextInputControllerBindings::SetMarkedText) |
Ryan Landay | d203467 | 2018-01-12 22:22:32 | [diff] [blame] | 115 | .SetMethod("setMarkedTextFromExistingText", |
| 116 | &TextInputControllerBindings::SetMarkedTextFromExistingText) |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 117 | .SetMethod("hasMarkedText", &TextInputControllerBindings::HasMarkedText) |
| 118 | .SetMethod("markedRange", &TextInputControllerBindings::MarkedRange) |
| 119 | .SetMethod("selectedRange", &TextInputControllerBindings::SelectedRange) |
| 120 | .SetMethod("firstRectForCharacterRange", |
| 121 | &TextInputControllerBindings::FirstRectForCharacterRange) |
ekaramad | 2daaf67 | 2016-11-10 20:29:01 | [diff] [blame] | 122 | .SetMethod("setComposition", &TextInputControllerBindings::SetComposition) |
| 123 | .SetMethod("forceTextInputStateUpdate", |
| 124 | &TextInputControllerBindings::ForceTextInputStateUpdate); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 125 | } |
| 126 | |
| 127 | void TextInputControllerBindings::InsertText(const std::string& text) { |
| 128 | if (controller_) |
| 129 | controller_->InsertText(text); |
| 130 | } |
| 131 | |
| 132 | void TextInputControllerBindings::UnmarkText() { |
| 133 | if (controller_) |
| 134 | controller_->UnmarkText(); |
| 135 | } |
| 136 | |
Ryan Landay | 7b5dbd5 | 2018-01-11 19:05:59 | [diff] [blame] | 137 | void TextInputControllerBindings::UnmarkAndUnselectText() { |
| 138 | if (controller_) |
| 139 | controller_->UnmarkAndUnselectText(); |
| 140 | } |
| 141 | |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 142 | void TextInputControllerBindings::DoCommand(const std::string& text) { |
| 143 | if (controller_) |
| 144 | controller_->DoCommand(text); |
| 145 | } |
| 146 | |
Ryan Landay | 9c680942 | 2018-01-17 07:04:15 | [diff] [blame] | 147 | void TextInputControllerBindings::ExtendSelectionAndDelete(int before, |
| 148 | int after) { |
| 149 | if (controller_) |
| 150 | controller_->ExtendSelectionAndDelete(before, after); |
| 151 | } |
| 152 | |
Ryan Landay | 6d163ae | 2018-01-17 06:58:06 | [diff] [blame] | 153 | void TextInputControllerBindings::DeleteSurroundingText(int before, int after) { |
| 154 | if (controller_) |
| 155 | controller_->DeleteSurroundingText(before, after); |
| 156 | } |
| 157 | |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 158 | void TextInputControllerBindings::SetMarkedText(const std::string& text, |
| 159 | int start, |
| 160 | int length) { |
| 161 | if (controller_) |
| 162 | controller_->SetMarkedText(text, start, length); |
| 163 | } |
| 164 | |
Ryan Landay | d203467 | 2018-01-12 22:22:32 | [diff] [blame] | 165 | void TextInputControllerBindings::SetMarkedTextFromExistingText(int start, |
| 166 | int end) { |
| 167 | if (controller_) |
| 168 | controller_->SetMarkedTextFromExistingText(start, end); |
| 169 | } |
| 170 | |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 171 | bool TextInputControllerBindings::HasMarkedText() { |
| 172 | return controller_ ? controller_->HasMarkedText() : false; |
| 173 | } |
| 174 | |
| 175 | std::vector<int> TextInputControllerBindings::MarkedRange() { |
| 176 | return controller_ ? controller_->MarkedRange() : std::vector<int>(); |
| 177 | } |
| 178 | |
| 179 | std::vector<int> TextInputControllerBindings::SelectedRange() { |
| 180 | return controller_ ? controller_->SelectedRange() : std::vector<int>(); |
| 181 | } |
| 182 | |
| 183 | std::vector<int> TextInputControllerBindings::FirstRectForCharacterRange( |
| 184 | unsigned location, |
| 185 | unsigned length) { |
| 186 | return controller_ ? controller_->FirstRectForCharacterRange(location, length) |
| 187 | : std::vector<int>(); |
| 188 | } |
| 189 | |
| 190 | void TextInputControllerBindings::SetComposition(const std::string& text) { |
| 191 | if (controller_) |
| 192 | controller_->SetComposition(text); |
| 193 | } |
ekaramad | 2daaf67 | 2016-11-10 20:29:01 | [diff] [blame] | 194 | void TextInputControllerBindings::ForceTextInputStateUpdate() { |
| 195 | if (controller_) |
| 196 | controller_->ForceTextInputStateUpdate(); |
| 197 | } |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 198 | // TextInputController --------------------------------------------------------- |
| 199 | |
Dave Tapuska | 13da016a | 2021-02-04 21:51:58 | [diff] [blame] | 200 | TextInputController::TextInputController( |
| 201 | WebFrameTestProxy* web_frame_test_proxy) |
| 202 | : web_frame_test_proxy_(web_frame_test_proxy) {} |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 203 | |
| 204 | TextInputController::~TextInputController() {} |
| 205 | |
lukasza | 8b6d5f3 | 2016-04-22 16:56:31 | [diff] [blame] | 206 | void TextInputController::Install(blink::WebLocalFrame* frame) { |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 207 | TextInputControllerBindings::Install(weak_factory_.GetWeakPtr(), frame); |
| 208 | } |
| 209 | |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 210 | void TextInputController::InsertText(const std::string& text) { |
ekaramad | c75b1b3b3 | 2016-12-02 03:57:52 | [diff] [blame] | 211 | if (auto* controller = GetInputMethodController()) { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 212 | controller->CommitText(blink::WebString::FromUTF8(text), |
Dave Tapuska | 7fa7521 | 2020-06-04 17:46:11 | [diff] [blame] | 213 | std::vector<ui::ImeTextSpan>(), blink::WebRange(), |
| 214 | 0); |
ekaramad | c75b1b3b3 | 2016-12-02 03:57:52 | [diff] [blame] | 215 | } |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 216 | } |
| 217 | |
| 218 | void TextInputController::UnmarkText() { |
ekaramad | c75b1b3b3 | 2016-12-02 03:57:52 | [diff] [blame] | 219 | if (auto* controller = GetInputMethodController()) { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 220 | controller->FinishComposingText( |
| 221 | blink::WebInputMethodController::kKeepSelection); |
ekaramad | c75b1b3b3 | 2016-12-02 03:57:52 | [diff] [blame] | 222 | } |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 223 | } |
| 224 | |
Ryan Landay | 7b5dbd5 | 2018-01-11 19:05:59 | [diff] [blame] | 225 | void TextInputController::UnmarkAndUnselectText() { |
| 226 | if (auto* controller = GetInputMethodController()) { |
| 227 | controller->FinishComposingText( |
| 228 | blink::WebInputMethodController::kDoNotKeepSelection); |
| 229 | } |
| 230 | } |
| 231 | |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 232 | void TextInputController::DoCommand(const std::string& text) { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 233 | if (view()->MainFrame()) { |
Ryan Landay | d203467 | 2018-01-12 22:22:32 | [diff] [blame] | 234 | CHECK(view()->MainFrame()->ToWebLocalFrame()) << "This function cannot be " |
| 235 | "called if the main frame " |
| 236 | "is not a local frame."; |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 237 | view()->MainFrame()->ToWebLocalFrame()->ExecuteCommand( |
| 238 | blink::WebString::FromUTF8(text)); |
yabinh | 8204efc | 2016-07-08 13:58:57 | [diff] [blame] | 239 | } |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 240 | } |
| 241 | |
Ryan Landay | 9c680942 | 2018-01-17 07:04:15 | [diff] [blame] | 242 | void TextInputController::ExtendSelectionAndDelete(int before, int after) { |
| 243 | if (view()->MainFrame()) { |
| 244 | CHECK(view()->MainFrame()->ToWebLocalFrame()) << "This function cannot be " |
| 245 | "called if the main frame " |
| 246 | "is not a local frame."; |
| 247 | view()->MainFrame()->ToWebLocalFrame()->ExtendSelectionAndDelete(before, |
| 248 | after); |
| 249 | } |
| 250 | } |
| 251 | |
Ryan Landay | 6d163ae | 2018-01-17 06:58:06 | [diff] [blame] | 252 | void TextInputController::DeleteSurroundingText(int before, int after) { |
| 253 | if (view()->MainFrame()) { |
| 254 | CHECK(view()->MainFrame()->ToWebLocalFrame()) << "This function cannot be " |
| 255 | "called if the main frame " |
| 256 | "is not a local frame."; |
| 257 | view()->MainFrame()->ToWebLocalFrame()->DeleteSurroundingText(before, |
| 258 | after); |
| 259 | } |
| 260 | } |
| 261 | |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 262 | void TextInputController::SetMarkedText(const std::string& text, |
| 263 | int start, |
| 264 | int length) { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 265 | blink::WebString web_text(blink::WebString::FromUTF8(text)); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 266 | |
| 267 | // Split underline into up to 3 elements (before, selection, and after). |
Dave Tapuska | 7fa7521 | 2020-06-04 17:46:11 | [diff] [blame] | 268 | std::vector<ui::ImeTextSpan> ime_text_spans; |
| 269 | ui::ImeTextSpan ime_text_span; |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 270 | if (!start) { |
Ryan Landay | 9e42fd74 | 2017-08-12 01:59:11 | [diff] [blame] | 271 | ime_text_span.end_offset = length; |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 272 | } else { |
Ryan Landay | 9e42fd74 | 2017-08-12 01:59:11 | [diff] [blame] | 273 | ime_text_span.end_offset = start; |
| 274 | ime_text_spans.push_back(ime_text_span); |
| 275 | ime_text_span.start_offset = start; |
| 276 | ime_text_span.end_offset = start + length; |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 277 | } |
Dave Tapuska | 7fa7521 | 2020-06-04 17:46:11 | [diff] [blame] | 278 | ime_text_span.thickness = ui::ImeTextSpan::Thickness::kThick; |
| 279 | ime_text_span.underline_style = ui::ImeTextSpan::UnderlineStyle::kSolid; |
Ryan Landay | 9e42fd74 | 2017-08-12 01:59:11 | [diff] [blame] | 280 | ime_text_spans.push_back(ime_text_span); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 281 | if (start + length < static_cast<int>(web_text.length())) { |
Ryan Landay | 9e42fd74 | 2017-08-12 01:59:11 | [diff] [blame] | 282 | ime_text_span.start_offset = ime_text_span.end_offset; |
| 283 | ime_text_span.end_offset = web_text.length(); |
Dave Tapuska | 7fa7521 | 2020-06-04 17:46:11 | [diff] [blame] | 284 | ime_text_span.thickness = ui::ImeTextSpan::Thickness::kThin; |
| 285 | ime_text_span.underline_style = ui::ImeTextSpan::UnderlineStyle::kSolid; |
Ryan Landay | 9e42fd74 | 2017-08-12 01:59:11 | [diff] [blame] | 286 | ime_text_spans.push_back(ime_text_span); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 287 | } |
| 288 | |
ekaramad | c75b1b3b3 | 2016-12-02 03:57:52 | [diff] [blame] | 289 | if (auto* controller = GetInputMethodController()) { |
Ryan Landay | 9e42fd74 | 2017-08-12 01:59:11 | [diff] [blame] | 290 | controller->SetComposition(web_text, ime_text_spans, blink::WebRange(), |
| 291 | start, start + length); |
ekaramad | c75b1b3b3 | 2016-12-02 03:57:52 | [diff] [blame] | 292 | } |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 293 | } |
| 294 | |
Ryan Landay | d203467 | 2018-01-12 22:22:32 | [diff] [blame] | 295 | void TextInputController::SetMarkedTextFromExistingText(int start, int end) { |
| 296 | if (!view()->MainFrame()) |
| 297 | return; |
| 298 | |
| 299 | CHECK(view()->MainFrame()->ToWebLocalFrame()) << "This function cannot be " |
| 300 | "called if the main frame " |
| 301 | "is not a local frame."; |
| 302 | |
| 303 | view()->MainFrame()->ToWebLocalFrame()->SetCompositionFromExistingText( |
Dave Tapuska | 7fa7521 | 2020-06-04 17:46:11 | [diff] [blame] | 304 | start, end, std::vector<ui::ImeTextSpan>()); |
Ryan Landay | d203467 | 2018-01-12 22:22:32 | [diff] [blame] | 305 | } |
| 306 | |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 307 | bool TextInputController::HasMarkedText() { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 308 | if (!view()->MainFrame()) |
yabinh | 8204efc | 2016-07-08 13:58:57 | [diff] [blame] | 309 | return false; |
| 310 | |
Ryan Landay | d203467 | 2018-01-12 22:22:32 | [diff] [blame] | 311 | CHECK(view()->MainFrame()->ToWebLocalFrame()) << "This function cannot be " |
| 312 | "called if the main frame " |
| 313 | "is not a local frame."; |
yabinh | 8204efc | 2016-07-08 13:58:57 | [diff] [blame] | 314 | |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 315 | return view()->MainFrame()->ToWebLocalFrame()->HasMarkedText(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 316 | } |
| 317 | |
| 318 | std::vector<int> TextInputController::MarkedRange() { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 319 | if (!view()->MainFrame()) |
[email protected] | 6f939712 | 2014-02-25 09:30:50 | [diff] [blame] | 320 | return std::vector<int>(); |
| 321 | |
Ryan Landay | d203467 | 2018-01-12 22:22:32 | [diff] [blame] | 322 | CHECK(view()->MainFrame()->ToWebLocalFrame()) << "This function cannot be " |
| 323 | "called if the main frame " |
| 324 | "is not a local frame."; |
yabinh | 8204efc | 2016-07-08 13:58:57 | [diff] [blame] | 325 | |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 326 | blink::WebRange range = view()->MainFrame()->ToWebLocalFrame()->MarkedRange(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 327 | std::vector<int> int_array(2); |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 328 | int_array[0] = range.StartOffset(); |
| 329 | int_array[1] = range.EndOffset(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 330 | |
| 331 | return int_array; |
| 332 | } |
| 333 | |
| 334 | std::vector<int> TextInputController::SelectedRange() { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 335 | if (!view()->MainFrame()) |
[email protected] | 6f939712 | 2014-02-25 09:30:50 | [diff] [blame] | 336 | return std::vector<int>(); |
| 337 | |
Ryan Landay | d203467 | 2018-01-12 22:22:32 | [diff] [blame] | 338 | CHECK(view()->MainFrame()->ToWebLocalFrame()) << "This function cannot be " |
| 339 | "called if the main frame " |
| 340 | "is not a local frame."; |
yabinh | 8204efc | 2016-07-08 13:58:57 | [diff] [blame] | 341 | |
| 342 | blink::WebRange range = |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 343 | view()->MainFrame()->ToWebLocalFrame()->SelectionRange(); |
| 344 | if (range.IsNull()) |
yosin | 702c78a3 | 2016-06-13 08:39:13 | [diff] [blame] | 345 | return std::vector<int>(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 346 | std::vector<int> int_array(2); |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 347 | int_array[0] = range.StartOffset(); |
| 348 | int_array[1] = range.EndOffset(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 349 | |
| 350 | return int_array; |
| 351 | } |
| 352 | |
| 353 | std::vector<int> TextInputController::FirstRectForCharacterRange( |
| 354 | unsigned location, |
| 355 | unsigned length) { |
Dave Tapuska | e8fe9b2 | 2021-01-21 20:38:21 | [diff] [blame] | 356 | gfx::Rect rect; |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 357 | if (!view()->FocusedFrame() || |
| 358 | !view()->FocusedFrame()->FirstRectForCharacterRange(location, length, |
lukasza | 8b6d5f3 | 2016-04-22 16:56:31 | [diff] [blame] | 359 | rect)) { |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 360 | return std::vector<int>(); |
[email protected] | 6f939712 | 2014-02-25 09:30:50 | [diff] [blame] | 361 | } |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 362 | |
| 363 | std::vector<int> int_array(4); |
Dave Tapuska | e8fe9b2 | 2021-01-21 20:38:21 | [diff] [blame] | 364 | int_array[0] = rect.x(); |
| 365 | int_array[1] = rect.y(); |
| 366 | int_array[2] = rect.width(); |
| 367 | int_array[3] = rect.height(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 368 | |
| 369 | return int_array; |
| 370 | } |
| 371 | |
| 372 | void TextInputController::SetComposition(const std::string& text) { |
| 373 | // Sends a keydown event with key code = 0xE5 to emulate input method |
| 374 | // behavior. |
Dave Tapuska | 347d60a | 2020-04-21 23:55:47 | [diff] [blame] | 375 | blink::WebKeyboardEvent key_down(blink::WebInputEvent::Type::kRawKeyDown, |
Daniel Cheng | 224569ee | 2018-04-25 05:45:06 | [diff] [blame] | 376 | blink::WebInputEvent::kNoModifiers, |
| 377 | ui::EventTimeForNow()); |
dtapuska | 899ac22 | 2017-01-03 18:09:16 | [diff] [blame] | 378 | |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 379 | key_down.windows_key_code = 0xE5; // VKEY_PROCESSKEY |
danakj | 763c240 | 2018-11-09 02:46:22 | [diff] [blame] | 380 | view()->MainFrameWidget()->HandleInputEvent( |
Dave Tapuska | cc788dd | 2020-05-11 22:33:56 | [diff] [blame] | 381 | blink::WebCoalescedInputEvent(key_down, ui::LatencyInfo())); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 382 | |
yabinh | dd6d1b6 | 2016-08-23 07:09:02 | [diff] [blame] | 383 | // The value returned by std::string::length() may not correspond to the |
| 384 | // actual number of encoded characters in sequences of multi-byte or |
| 385 | // variable-length characters. |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 386 | blink::WebString newText = blink::WebString::FromUTF8(text); |
yabinh | dd6d1b6 | 2016-08-23 07:09:02 | [diff] [blame] | 387 | size_t textLength = newText.length(); |
| 388 | |
Dave Tapuska | 7fa7521 | 2020-06-04 17:46:11 | [diff] [blame] | 389 | std::vector<ui::ImeTextSpan> ime_text_spans; |
| 390 | ime_text_spans.push_back(ui::ImeTextSpan( |
| 391 | ui::ImeTextSpan::Type::kComposition, 0, textLength, |
| 392 | ui::ImeTextSpan::Thickness::kThin, |
| 393 | ui::ImeTextSpan::UnderlineStyle::kSolid, SK_ColorTRANSPARENT)); |
ekaramad | c75b1b3b3 | 2016-12-02 03:57:52 | [diff] [blame] | 394 | if (auto* controller = GetInputMethodController()) { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 395 | controller->SetComposition( |
Dave Tapuska | 7fa7521 | 2020-06-04 17:46:11 | [diff] [blame] | 396 | newText, blink::WebVector<ui::ImeTextSpan>(std::move(ime_text_spans)), |
ekaramad | ce32ef9f | 2017-02-09 17:33:56 | [diff] [blame] | 397 | blink::WebRange(), textLength, textLength); |
ekaramad | c75b1b3b3 | 2016-12-02 03:57:52 | [diff] [blame] | 398 | } |
lukasza | 8b6d5f3 | 2016-04-22 16:56:31 | [diff] [blame] | 399 | } |
| 400 | |
ekaramad | 2daaf67 | 2016-11-10 20:29:01 | [diff] [blame] | 401 | void TextInputController::ForceTextInputStateUpdate() { |
Dave Tapuska | a5c5348510 | 2020-12-01 21:31:02 | [diff] [blame] | 402 | blink::WebFrameWidget* frame_widget = |
Dave Tapuska | 13da016a | 2021-02-04 21:51:58 | [diff] [blame] | 403 | web_frame_test_proxy_->GetLocalRootWebFrameWidget(); |
Dave Tapuska | a5c5348510 | 2020-12-01 21:31:02 | [diff] [blame] | 404 | frame_widget->ShowVirtualKeyboard(); |
ekaramad | 2daaf67 | 2016-11-10 20:29:01 | [diff] [blame] | 405 | } |
| 406 | |
lukasza | 8b6d5f3 | 2016-04-22 16:56:31 | [diff] [blame] | 407 | blink::WebView* TextInputController::view() { |
Dave Tapuska | 13da016a | 2021-02-04 21:51:58 | [diff] [blame] | 408 | return web_frame_test_proxy_->GetWebFrame()->View(); |
[email protected] | f751653a9 | 2014-02-18 16:32:55 | [diff] [blame] | 409 | } |
| 410 | |
ekaramad | c75b1b3b3 | 2016-12-02 03:57:52 | [diff] [blame] | 411 | blink::WebInputMethodController* |
| 412 | TextInputController::GetInputMethodController() { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 413 | if (!view()->MainFrame()) |
ekaramad | c75b1b3b3 | 2016-12-02 03:57:52 | [diff] [blame] | 414 | return nullptr; |
| 415 | |
Kent Tamura | 21d1de6 | 2018-12-10 04:45:20 | [diff] [blame] | 416 | // TODO(lukasza): Finish adding OOPIF support to the web tests harness. |
Daniel Cheng | 3c82943 | 2017-06-19 03:42:31 | [diff] [blame] | 417 | CHECK(view()->MainFrame()->IsWebLocalFrame()) |
| 418 | << "WebView does not have a local main frame and" |
| 419 | " cannot handle input method controller tasks."; |
| 420 | |
danakj | e3e48d4 | 2020-05-01 23:47:33 | [diff] [blame] | 421 | return view()->MainFrameWidget()->GetActiveWebInputMethodController(); |
ekaramad | 2daaf67 | 2016-11-10 20:29:01 | [diff] [blame] | 422 | } |
| 423 | |
danakj | 741848a | 2020-04-07 22:48:06 | [diff] [blame] | 424 | } // namespace content |