dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "content/renderer/input/frame_input_handler_impl.h" |
| 6 | |
| 7 | #include <utility> |
| 8 | |
| 9 | #include "base/bind.h" |
| 10 | #include "base/debug/stack_trace.h" |
| 11 | #include "base/logging.h" |
Ryan Landay | 69ac1e4 | 2017-09-14 02:17:38 | [diff] [blame] | 12 | #include "content/common/input/ime_text_span_conversions.h" |
Sadrul Habib Chowdhury | 31c9871 | 2018-12-11 04:15:13 | [diff] [blame] | 13 | #include "content/renderer/compositor/layer_tree_view.h" |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 14 | #include "content/renderer/ime_event_guard.h" |
Dave Tapuska | 525eb15e | 2017-08-17 21:05:50 | [diff] [blame] | 15 | #include "content/renderer/input/widget_input_handler_manager.h" |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 16 | #include "content/renderer/render_thread_impl.h" |
| 17 | #include "content/renderer/render_view_impl.h" |
| 18 | #include "content/renderer/render_widget.h" |
Blink Reformat | a30d423 | 2018-04-07 15:31:06 | [diff] [blame] | 19 | #include "third_party/blink/public/web/web_input_method_controller.h" |
| 20 | #include "third_party/blink/public/web/web_local_frame.h" |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 21 | |
| 22 | namespace content { |
| 23 | |
| 24 | FrameInputHandlerImpl::FrameInputHandlerImpl( |
| 25 | base::WeakPtr<RenderFrameImpl> render_frame, |
| 26 | mojom::FrameInputHandlerRequest request) |
| 27 | : binding_(this), |
| 28 | render_frame_(render_frame), |
Albert J. Wong | 7bbf22d | 2018-12-20 00:27:27 | [diff] [blame^] | 29 | input_event_queue_( |
| 30 | render_frame->GetLocalRootRenderWidget()->GetInputEventQueue()), |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 31 | main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
Albert J. Wong | 7bbf22d | 2018-12-20 00:27:27 | [diff] [blame^] | 32 | weak_ptr_factory_(this) { |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 33 | weak_this_ = weak_ptr_factory_.GetWeakPtr(); |
| 34 | // If we have created an input event queue move the mojo request over to the |
| 35 | // compositor thread. |
Dave Tapuska | 04bc5ee9 | 2018-04-17 19:03:31 | [diff] [blame] | 36 | if (RenderThreadImpl::current() && |
| 37 | RenderThreadImpl::current()->compositor_task_runner() && |
Dave Tapuska | 9db8084 | 2017-07-24 17:24:26 | [diff] [blame] | 38 | input_event_queue_) { |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 39 | // Mojo channel bound on compositor thread. |
| 40 | RenderThreadImpl::current()->compositor_task_runner()->PostTask( |
| 41 | FROM_HERE, base::BindOnce(&FrameInputHandlerImpl::BindNow, |
| 42 | base::Unretained(this), std::move(request))); |
| 43 | } else { |
| 44 | // Mojo channel bound on main thread. |
| 45 | BindNow(std::move(request)); |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | FrameInputHandlerImpl::~FrameInputHandlerImpl() {} |
| 50 | |
| 51 | // static |
| 52 | void FrameInputHandlerImpl::CreateMojoService( |
| 53 | base::WeakPtr<RenderFrameImpl> render_frame, |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 54 | mojom::FrameInputHandlerRequest request) { |
| 55 | DCHECK(render_frame); |
| 56 | |
| 57 | // Owns itself. Will be deleted when message pipe is destroyed. |
| 58 | new FrameInputHandlerImpl(render_frame, std::move(request)); |
| 59 | } |
| 60 | |
Shimi Zhang | e697c83 | 2018-10-04 23:19:17 | [diff] [blame] | 61 | void FrameInputHandlerImpl::RunOnMainThread(base::OnceClosure closure) { |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 62 | if (input_event_queue_) { |
Shimi Zhang | e697c83 | 2018-10-04 23:19:17 | [diff] [blame] | 63 | input_event_queue_->QueueClosure(std::move(closure)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 64 | } else { |
Shimi Zhang | e697c83 | 2018-10-04 23:19:17 | [diff] [blame] | 65 | std::move(closure).Run(); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 66 | } |
| 67 | } |
| 68 | |
| 69 | void FrameInputHandlerImpl::SetCompositionFromExistingText( |
| 70 | int32_t start, |
| 71 | int32_t end, |
Ryan Landay | 9e42fd74 | 2017-08-12 01:59:11 | [diff] [blame] | 72 | const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) { |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 73 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 74 | RunOnMainThread( |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 75 | base::BindOnce(&FrameInputHandlerImpl::SetCompositionFromExistingText, |
| 76 | weak_this_, start, end, ui_ime_text_spans)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 77 | return; |
| 78 | } |
| 79 | |
| 80 | if (!render_frame_) |
| 81 | return; |
| 82 | |
Albert J. Wong | 7bbf22d | 2018-12-20 00:27:27 | [diff] [blame^] | 83 | ImeEventGuard guard(render_frame_->GetLocalRootRenderWidget()); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 84 | |
Manuel Rego Casasnovas | 6743b45 | 2018-03-22 20:42:39 | [diff] [blame] | 85 | render_frame_->GetWebFrame()->SetCompositionFromExistingText( |
| 86 | start, end, ConvertUiImeTextSpansToBlinkImeTextSpans(ui_ime_text_spans)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 87 | } |
| 88 | |
| 89 | void FrameInputHandlerImpl::ExtendSelectionAndDelete(int32_t before, |
| 90 | int32_t after) { |
| 91 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 92 | RunOnMainThread( |
| 93 | base::BindOnce(&FrameInputHandlerImpl::ExtendSelectionAndDelete, |
| 94 | weak_this_, before, after)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 95 | return; |
| 96 | } |
| 97 | if (!render_frame_) |
| 98 | return; |
| 99 | render_frame_->GetWebFrame()->ExtendSelectionAndDelete(before, after); |
| 100 | } |
| 101 | |
| 102 | void FrameInputHandlerImpl::DeleteSurroundingText(int32_t before, |
| 103 | int32_t after) { |
| 104 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 105 | RunOnMainThread( |
| 106 | base::BindOnce(&FrameInputHandlerImpl::DeleteSurroundingText, |
| 107 | weak_this_, before, after)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 108 | return; |
| 109 | } |
| 110 | if (!render_frame_) |
| 111 | return; |
| 112 | render_frame_->GetWebFrame()->DeleteSurroundingText(before, after); |
| 113 | } |
| 114 | |
| 115 | void FrameInputHandlerImpl::DeleteSurroundingTextInCodePoints(int32_t before, |
| 116 | int32_t after) { |
| 117 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 118 | RunOnMainThread(base::BindOnce( |
| 119 | &FrameInputHandlerImpl::DeleteSurroundingTextInCodePoints, weak_this_, |
| 120 | before, after)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 121 | return; |
| 122 | } |
| 123 | if (!render_frame_) |
| 124 | return; |
| 125 | render_frame_->GetWebFrame()->DeleteSurroundingTextInCodePoints(before, |
| 126 | after); |
| 127 | } |
| 128 | |
| 129 | void FrameInputHandlerImpl::SetEditableSelectionOffsets(int32_t start, |
| 130 | int32_t end) { |
| 131 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 132 | RunOnMainThread( |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 133 | base::BindOnce(&FrameInputHandlerImpl::SetEditableSelectionOffsets, |
| 134 | weak_this_, start, end)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 135 | return; |
| 136 | } |
| 137 | if (!render_frame_) |
| 138 | return; |
Dave Tapuska | 8e304aa | 2017-11-15 17:29:46 | [diff] [blame] | 139 | HandlingState handling_state(render_frame_, UpdateState::kIsSelectingRange); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 140 | render_frame_->GetWebFrame()->SetEditableSelectionOffsets(start, end); |
| 141 | } |
| 142 | |
| 143 | void FrameInputHandlerImpl::ExecuteEditCommand( |
| 144 | const std::string& command, |
| 145 | const base::Optional<base::string16>& value) { |
| 146 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 147 | RunOnMainThread(base::BindOnce(&FrameInputHandlerImpl::ExecuteEditCommand, |
| 148 | weak_this_, command, value)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 149 | return; |
| 150 | } |
| 151 | if (!render_frame_) |
| 152 | return; |
| 153 | if (value) { |
| 154 | render_frame_->GetWebFrame()->ExecuteCommand( |
| 155 | blink::WebString::FromUTF8(command), |
| 156 | blink::WebString::FromUTF16(value.value())); |
| 157 | return; |
| 158 | } |
| 159 | |
| 160 | render_frame_->GetWebFrame()->ExecuteCommand( |
| 161 | blink::WebString::FromUTF8(command)); |
| 162 | } |
| 163 | |
| 164 | void FrameInputHandlerImpl::Undo() { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 165 | RunOnMainThread( |
| 166 | base::BindOnce(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, |
| 167 | weak_this_, "Undo", UpdateState::kNone)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 168 | } |
| 169 | |
| 170 | void FrameInputHandlerImpl::Redo() { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 171 | RunOnMainThread( |
| 172 | base::BindOnce(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, |
| 173 | weak_this_, "Redo", UpdateState::kNone)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 174 | } |
| 175 | |
| 176 | void FrameInputHandlerImpl::Cut() { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 177 | RunOnMainThread( |
| 178 | base::BindOnce(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, |
| 179 | weak_this_, "Cut", UpdateState::kIsSelectingRange)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 180 | } |
| 181 | |
| 182 | void FrameInputHandlerImpl::Copy() { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 183 | RunOnMainThread( |
| 184 | base::BindOnce(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, |
| 185 | weak_this_, "Copy", UpdateState::kIsSelectingRange)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 186 | } |
| 187 | |
| 188 | void FrameInputHandlerImpl::CopyToFindPboard() { |
| 189 | #if defined(OS_MACOSX) |
| 190 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 191 | RunOnMainThread( |
| 192 | base::Bind(&FrameInputHandlerImpl::CopyToFindPboard, weak_this_)); |
| 193 | return; |
| 194 | } |
| 195 | if (!render_frame_) |
| 196 | return; |
| 197 | render_frame_->OnCopyToFindPboard(); |
| 198 | #endif |
| 199 | } |
| 200 | |
| 201 | void FrameInputHandlerImpl::Paste() { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 202 | RunOnMainThread( |
| 203 | base::BindOnce(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, |
| 204 | weak_this_, "Paste", UpdateState::kIsPasting)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 205 | } |
| 206 | |
| 207 | void FrameInputHandlerImpl::PasteAndMatchStyle() { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 208 | RunOnMainThread(base::BindOnce( |
| 209 | &FrameInputHandlerImpl::ExecuteCommandOnMainThread, weak_this_, |
| 210 | "PasteAndMatchStyle", UpdateState::kIsPasting)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 211 | } |
| 212 | |
| 213 | void FrameInputHandlerImpl::Replace(const base::string16& word) { |
| 214 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 215 | RunOnMainThread( |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 216 | base::BindOnce(&FrameInputHandlerImpl::Replace, weak_this_, word)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 217 | return; |
| 218 | } |
| 219 | if (!render_frame_) |
| 220 | return; |
| 221 | blink::WebLocalFrame* frame = render_frame_->GetWebFrame(); |
Tessa Nijssen | cb4583b | 2018-07-31 20:09:17 | [diff] [blame] | 222 | if (!frame->HasSelection()) |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 223 | frame->SelectWordAroundCaret(); |
| 224 | frame->ReplaceSelection(blink::WebString::FromUTF16(word)); |
| 225 | render_frame_->SyncSelectionIfRequired(); |
| 226 | } |
| 227 | |
| 228 | void FrameInputHandlerImpl::ReplaceMisspelling(const base::string16& word) { |
| 229 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 230 | RunOnMainThread(base::BindOnce(&FrameInputHandlerImpl::ReplaceMisspelling, |
| 231 | weak_this_, word)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 232 | return; |
| 233 | } |
| 234 | if (!render_frame_) |
| 235 | return; |
| 236 | blink::WebLocalFrame* frame = render_frame_->GetWebFrame(); |
| 237 | if (!frame->HasSelection()) |
| 238 | return; |
| 239 | frame->ReplaceMisspelledRange(blink::WebString::FromUTF16(word)); |
| 240 | } |
| 241 | |
| 242 | void FrameInputHandlerImpl::Delete() { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 243 | RunOnMainThread( |
| 244 | base::BindOnce(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, |
| 245 | weak_this_, "Delete", UpdateState::kNone)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | void FrameInputHandlerImpl::SelectAll() { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 249 | RunOnMainThread( |
| 250 | base::BindOnce(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, |
| 251 | weak_this_, "SelectAll", UpdateState::kIsSelectingRange)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 252 | } |
| 253 | |
| 254 | void FrameInputHandlerImpl::CollapseSelection() { |
| 255 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 256 | RunOnMainThread( |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 257 | base::BindOnce(&FrameInputHandlerImpl::CollapseSelection, weak_this_)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 258 | return; |
| 259 | } |
| 260 | |
| 261 | if (!render_frame_) |
| 262 | return; |
ekaramad | d503ac6 | 2017-07-19 23:26:06 | [diff] [blame] | 263 | const blink::WebRange& range = render_frame_->GetWebFrame() |
| 264 | ->GetInputMethodController() |
| 265 | ->GetSelectionOffsets(); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 266 | if (range.IsNull()) |
| 267 | return; |
| 268 | |
Dave Tapuska | f02060a | 2017-10-27 16:47:40 | [diff] [blame] | 269 | HandlingState handling_state(render_frame_, UpdateState::kIsSelectingRange); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 270 | render_frame_->GetWebFrame()->SelectRange( |
Shimi Zhang | 37deeb2 | 2017-09-28 00:59:01 | [diff] [blame] | 271 | blink::WebRange(range.EndOffset(), 0), |
| 272 | blink::WebLocalFrame::kHideSelectionHandle, |
| 273 | blink::mojom::SelectionMenuBehavior::kHide); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 274 | } |
| 275 | |
| 276 | void FrameInputHandlerImpl::SelectRange(const gfx::Point& base, |
| 277 | const gfx::Point& extent) { |
| 278 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 279 | // TODO(dtapuska): This event should be coalesced. Chrome IPC uses |
| 280 | // one outstanding event and an ACK to handle coalescing on the browser |
| 281 | // side. We should be able to clobber them in the main thread event queue. |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 282 | RunOnMainThread(base::BindOnce(&FrameInputHandlerImpl::SelectRange, |
| 283 | weak_this_, base, extent)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 284 | return; |
| 285 | } |
| 286 | |
| 287 | if (!render_frame_) |
| 288 | return; |
Albert J. Wong | 7fcddfa | 2018-05-29 22:13:21 | [diff] [blame] | 289 | RenderWidget* window_widget = render_frame_->render_view()->GetWidget(); |
Dave Tapuska | f02060a | 2017-10-27 16:47:40 | [diff] [blame] | 290 | HandlingState handling_state(render_frame_, UpdateState::kIsSelectingRange); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 291 | render_frame_->GetWebFrame()->SelectRange( |
Albert J. Wong | 7fcddfa | 2018-05-29 22:13:21 | [diff] [blame] | 292 | window_widget->ConvertWindowPointToViewport(base), |
| 293 | window_widget->ConvertWindowPointToViewport(extent)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 294 | } |
| 295 | |
Shimi Zhang | e697c83 | 2018-10-04 23:19:17 | [diff] [blame] | 296 | #if defined(OS_ANDROID) |
| 297 | void FrameInputHandlerImpl::SelectWordAroundCaret( |
| 298 | SelectWordAroundCaretCallback callback) { |
| 299 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 300 | RunOnMainThread( |
| 301 | base::BindOnce(&FrameInputHandlerImpl::SelectWordAroundCaret, |
| 302 | weak_this_, std::move(callback))); |
| 303 | return; |
| 304 | } |
| 305 | |
| 306 | bool did_select = false; |
| 307 | int start_adjust = 0; |
| 308 | int end_adjust = 0; |
| 309 | if (render_frame_) { |
| 310 | blink::WebLocalFrame* frame = render_frame_->GetWebFrame(); |
| 311 | blink::WebRange initial_range = frame->SelectionRange(); |
Albert J. Wong | 7bbf22d | 2018-12-20 00:27:27 | [diff] [blame^] | 312 | render_frame_->GetLocalRootRenderWidget()->SetHandlingInputEvent(true); |
Shimi Zhang | e697c83 | 2018-10-04 23:19:17 | [diff] [blame] | 313 | if (!initial_range.IsNull()) |
| 314 | did_select = frame->SelectWordAroundCaret(); |
| 315 | if (did_select) { |
| 316 | blink::WebRange adjusted_range = frame->SelectionRange(); |
| 317 | DCHECK(!adjusted_range.IsNull()); |
| 318 | start_adjust = adjusted_range.StartOffset() - initial_range.StartOffset(); |
| 319 | end_adjust = adjusted_range.EndOffset() - initial_range.EndOffset(); |
| 320 | } |
Albert J. Wong | 7bbf22d | 2018-12-20 00:27:27 | [diff] [blame^] | 321 | render_frame_->GetLocalRootRenderWidget()->SetHandlingInputEvent(false); |
Shimi Zhang | e697c83 | 2018-10-04 23:19:17 | [diff] [blame] | 322 | } |
| 323 | |
| 324 | // If the mojom channel is registered with compositor thread, we have to run |
| 325 | // the callback on compositor thread. Otherwise run it on main thread. Mojom |
| 326 | // requires the callback runs on the same thread. |
| 327 | if (RenderThreadImpl::current() && |
| 328 | RenderThreadImpl::current()->compositor_task_runner() && |
| 329 | input_event_queue_) { |
| 330 | RenderThreadImpl::current()->compositor_task_runner()->PostTask( |
| 331 | FROM_HERE, base::BindOnce(std::move(callback), did_select, start_adjust, |
| 332 | end_adjust)); |
| 333 | } else { |
| 334 | std::move(callback).Run(did_select, start_adjust, end_adjust); |
| 335 | } |
| 336 | } |
| 337 | #endif // defined(OS_ANDROID) |
| 338 | |
Shimi Zhang | 37deeb2 | 2017-09-28 00:59:01 | [diff] [blame] | 339 | void FrameInputHandlerImpl::AdjustSelectionByCharacterOffset( |
| 340 | int32_t start, |
| 341 | int32_t end, |
| 342 | blink::mojom::SelectionMenuBehavior selection_menu_behavior) { |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 343 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 344 | RunOnMainThread( |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 345 | base::BindOnce(&FrameInputHandlerImpl::AdjustSelectionByCharacterOffset, |
| 346 | weak_this_, start, end, selection_menu_behavior)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 347 | return; |
| 348 | } |
| 349 | |
| 350 | if (!render_frame_) |
| 351 | return; |
ekaramad | d503ac6 | 2017-07-19 23:26:06 | [diff] [blame] | 352 | blink::WebRange range = render_frame_->GetWebFrame() |
| 353 | ->GetInputMethodController() |
| 354 | ->GetSelectionOffsets(); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 355 | if (range.IsNull()) |
| 356 | return; |
| 357 | |
| 358 | // Sanity checks to disallow empty and out of range selections. |
| 359 | if (start - end > range.length() || range.StartOffset() + start < 0) |
| 360 | return; |
| 361 | |
Dave Tapuska | f02060a | 2017-10-27 16:47:40 | [diff] [blame] | 362 | HandlingState handling_state(render_frame_, UpdateState::kIsSelectingRange); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 363 | // A negative adjust amount moves the selection towards the beginning of |
| 364 | // the document, a positive amount moves the selection towards the end of |
| 365 | // the document. |
| 366 | render_frame_->GetWebFrame()->SelectRange( |
| 367 | blink::WebRange(range.StartOffset() + start, |
| 368 | range.length() + end - start), |
Shimi Zhang | 37deeb2 | 2017-09-28 00:59:01 | [diff] [blame] | 369 | blink::WebLocalFrame::kPreserveHandleVisibility, selection_menu_behavior); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 370 | } |
| 371 | |
| 372 | void FrameInputHandlerImpl::MoveRangeSelectionExtent(const gfx::Point& extent) { |
| 373 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 374 | // TODO(dtapuska): This event should be coalesced. Chrome IPC uses |
| 375 | // one outstanding event and an ACK to handle coalescing on the browser |
| 376 | // side. We should be able to clobber them in the main thread event queue. |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 377 | RunOnMainThread(base::BindOnce( |
| 378 | &FrameInputHandlerImpl::MoveRangeSelectionExtent, weak_this_, extent)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 379 | return; |
| 380 | } |
| 381 | |
| 382 | if (!render_frame_) |
| 383 | return; |
Dave Tapuska | f02060a | 2017-10-27 16:47:40 | [diff] [blame] | 384 | HandlingState handling_state(render_frame_, UpdateState::kIsSelectingRange); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 385 | render_frame_->GetWebFrame()->MoveRangeSelectionExtent( |
Albert J. Wong | 7fcddfa | 2018-05-29 22:13:21 | [diff] [blame] | 386 | render_frame_->render_view()->GetWidget()->ConvertWindowPointToViewport( |
| 387 | extent)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 388 | } |
| 389 | |
Dave Tapuska | b336b92 | 2017-07-06 19:24:05 | [diff] [blame] | 390 | void FrameInputHandlerImpl::ScrollFocusedEditableNodeIntoRect( |
| 391 | const gfx::Rect& rect) { |
| 392 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 393 | RunOnMainThread(base::BindOnce( |
| 394 | &FrameInputHandlerImpl::ScrollFocusedEditableNodeIntoRect, weak_this_, |
| 395 | rect)); |
Dave Tapuska | b336b92 | 2017-07-06 19:24:05 | [diff] [blame] | 396 | return; |
| 397 | } |
| 398 | |
| 399 | if (!render_frame_) |
| 400 | return; |
| 401 | |
EhsanK | bd2cea99 | 2017-11-23 18:49:08 | [diff] [blame] | 402 | render_frame_->ScrollFocusedEditableElementIntoRect(rect); |
Dave Tapuska | b336b92 | 2017-07-06 19:24:05 | [diff] [blame] | 403 | } |
| 404 | |
| 405 | void FrameInputHandlerImpl::MoveCaret(const gfx::Point& point) { |
| 406 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 407 | RunOnMainThread( |
tzik | 37afd2a | 2018-10-17 06:40:18 | [diff] [blame] | 408 | base::BindOnce(&FrameInputHandlerImpl::MoveCaret, weak_this_, point)); |
Dave Tapuska | b336b92 | 2017-07-06 19:24:05 | [diff] [blame] | 409 | return; |
| 410 | } |
| 411 | |
| 412 | if (!render_frame_) |
| 413 | return; |
| 414 | |
Dave Tapuska | b336b92 | 2017-07-06 19:24:05 | [diff] [blame] | 415 | render_frame_->GetWebFrame()->MoveCaretSelection( |
Albert J. Wong | 7fcddfa | 2018-05-29 22:13:21 | [diff] [blame] | 416 | render_frame_->render_view()->GetWidget()->ConvertWindowPointToViewport( |
| 417 | point)); |
Dave Tapuska | b336b92 | 2017-07-06 19:24:05 | [diff] [blame] | 418 | } |
| 419 | |
Dave Tapuska | 525eb15e | 2017-08-17 21:05:50 | [diff] [blame] | 420 | void FrameInputHandlerImpl::GetWidgetInputHandler( |
Dave Tapuska | b66c28f | 2017-11-15 17:18:47 | [diff] [blame] | 421 | mojom::WidgetInputHandlerAssociatedRequest interface_request, |
| 422 | mojom::WidgetInputHandlerHostPtr host) { |
Dave Tapuska | 525eb15e | 2017-08-17 21:05:50 | [diff] [blame] | 423 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 424 | main_thread_task_runner_->PostTask( |
| 425 | FROM_HERE, base::BindOnce(&FrameInputHandlerImpl::GetWidgetInputHandler, |
Dave Tapuska | b66c28f | 2017-11-15 17:18:47 | [diff] [blame] | 426 | weak_this_, std::move(interface_request), |
| 427 | std::move(host))); |
Dave Tapuska | 525eb15e | 2017-08-17 21:05:50 | [diff] [blame] | 428 | return; |
| 429 | } |
| 430 | if (!render_frame_) |
| 431 | return; |
Albert J. Wong | 7bbf22d | 2018-12-20 00:27:27 | [diff] [blame^] | 432 | render_frame_->GetLocalRootRenderWidget() |
Dave Tapuska | 525eb15e | 2017-08-17 21:05:50 | [diff] [blame] | 433 | ->widget_input_handler_manager() |
Dave Tapuska | b66c28f | 2017-11-15 17:18:47 | [diff] [blame] | 434 | ->AddAssociatedInterface(std::move(interface_request), std::move(host)); |
Dave Tapuska | 525eb15e | 2017-08-17 21:05:50 | [diff] [blame] | 435 | } |
| 436 | |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 437 | void FrameInputHandlerImpl::ExecuteCommandOnMainThread( |
| 438 | const std::string& command, |
| 439 | UpdateState update_state) { |
| 440 | if (!render_frame_) |
| 441 | return; |
| 442 | |
Dave Tapuska | f02060a | 2017-10-27 16:47:40 | [diff] [blame] | 443 | HandlingState handling_state(render_frame_, update_state); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 444 | render_frame_->GetWebFrame()->ExecuteCommand( |
| 445 | blink::WebString::FromUTF8(command)); |
| 446 | } |
| 447 | |
| 448 | void FrameInputHandlerImpl::Release() { |
| 449 | if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
| 450 | // Close the binding on the compositor thread first before telling the main |
| 451 | // thread to delete this object. |
| 452 | binding_.Close(); |
| 453 | main_thread_task_runner_->PostTask( |
tzik | 1076ee2 | 2017-08-25 04:03:57 | [diff] [blame] | 454 | FROM_HERE, base::BindOnce(&FrameInputHandlerImpl::Release, weak_this_)); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 455 | return; |
| 456 | } |
| 457 | delete this; |
| 458 | } |
| 459 | |
| 460 | void FrameInputHandlerImpl::BindNow(mojom::FrameInputHandlerRequest request) { |
| 461 | binding_.Bind(std::move(request)); |
| 462 | binding_.set_connection_error_handler( |
tzik | 1076ee2 | 2017-08-25 04:03:57 | [diff] [blame] | 463 | base::BindOnce(&FrameInputHandlerImpl::Release, base::Unretained(this))); |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 464 | } |
| 465 | |
| 466 | FrameInputHandlerImpl::HandlingState::HandlingState( |
Dave Tapuska | f02060a | 2017-10-27 16:47:40 | [diff] [blame] | 467 | const base::WeakPtr<RenderFrameImpl>& render_frame, |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 468 | UpdateState state) |
| 469 | : render_frame_(render_frame), |
| 470 | original_select_range_value_(render_frame->handling_select_range()), |
| 471 | original_pasting_value_(render_frame->IsPasting()) { |
| 472 | switch (state) { |
| 473 | case UpdateState::kIsPasting: |
| 474 | render_frame->set_is_pasting(true); |
Nico Weber | 39f9c29 | 2018-01-29 18:51:12 | [diff] [blame] | 475 | FALLTHROUGH; // Matches RenderFrameImpl::OnPaste() which sets both. |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 476 | case UpdateState::kIsSelectingRange: |
| 477 | render_frame->set_handling_select_range(true); |
| 478 | break; |
| 479 | case UpdateState::kNone: |
| 480 | break; |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | FrameInputHandlerImpl::HandlingState::~HandlingState() { |
Dave Tapuska | f02060a | 2017-10-27 16:47:40 | [diff] [blame] | 485 | // RenderFrame may have been destroyed while this object was on the stack. |
| 486 | if (!render_frame_) |
| 487 | return; |
dtapuska | 9d46ef7d | 2017-05-26 19:06:06 | [diff] [blame] | 488 | render_frame_->set_handling_select_range(original_select_range_value_); |
| 489 | render_frame_->set_is_pasting(original_pasting_value_); |
| 490 | } |
| 491 | |
| 492 | } // namespace content |