Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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" | |
| 12 #include "content/renderer/ime_event_guard.h" | |
| 13 #include "content/renderer/render_thread_impl.h" | |
| 14 #include "content/renderer/render_view_impl.h" | |
| 15 #include "content/renderer/render_widget.h" | |
| 16 #include "third_party/WebKit/public/web/WebLocalFrame.h" | |
| 17 | |
| 18 namespace content { | |
| 19 | |
| 20 FrameInputHandlerImpl::FrameInputHandlerImpl( | |
| 21 base::WeakPtr<RenderFrameImpl> render_frame, | |
| 22 mojom::FrameInputHandlerRequest request) | |
| 23 : binding_(this), | |
| 24 render_frame_(render_frame), | |
| 25 input_event_queue_( | |
| 26 render_frame->GetRenderWidget()->GetInputEventQueue()) { | |
| 27 // Once the binding is connected the error handler will be set to | |
| 28 // Release. | |
| 29 AddRef(); | |
| 30 | |
| 31 // If we have created an input event queue move the mojo request over to the | |
| 32 // compositor thread. | |
| 33 if (input_event_queue_) { | |
| 34 // Mojo channel bound on compositor thread. | |
| 35 RenderThreadImpl::current()->compositor_task_runner()->PostTask( | |
| 36 FROM_HERE, base::BindOnce(&FrameInputHandlerImpl::BindOnCompositor, | |
| 37 this, std::move(request))); | |
| 38 } else { | |
| 39 // Mojo channel bound on main thread. | |
| 40 BindNow(std::move(request)); | |
| 41 } | |
| 42 main_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
|
dcheng
2017/05/25 00:03:58
Nit: bind this in the initializer list for consist
dtapuska
2017/05/26 14:02:06
Done.
| |
| 43 } | |
| 44 | |
| 45 FrameInputHandlerImpl::~FrameInputHandlerImpl() {} | |
| 46 | |
| 47 // static | |
| 48 void FrameInputHandlerImpl::CreateMojoService( | |
| 49 base::WeakPtr<RenderFrameImpl> render_frame, | |
| 50 const service_manager::BindSourceInfo& source_info, | |
| 51 mojom::FrameInputHandlerRequest request) { | |
| 52 DCHECK(render_frame); | |
| 53 | |
| 54 // Owns itself. Will be deleted when message pipe is destroyed. | |
| 55 new FrameInputHandlerImpl(render_frame, std::move(request)); | |
| 56 } | |
| 57 | |
| 58 void FrameInputHandlerImpl::RunOnMainThread(const base::Closure& closure) { | |
| 59 if (input_event_queue_) { | |
| 60 input_event_queue_->QueueClosure(closure); | |
| 61 } else { | |
| 62 closure.Run(); | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 void FrameInputHandlerImpl::SetCompositionFromExistingText( | |
| 67 int32_t start, | |
| 68 int32_t end, | |
| 69 const std::vector<ui::CompositionUnderline>& ui_underlines) { | |
| 70 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 71 RunOnMainThread( | |
| 72 base::Bind(&FrameInputHandlerImpl::SetCompositionFromExistingText, this, | |
|
dcheng
2017/05/25 00:03:58
It's safe to vend weak pointers from another threa
dtapuska
2017/05/26 14:02:06
Done. Although I needed to clear the bindings in t
| |
| 73 start, end, ui_underlines)); | |
| 74 return; | |
| 75 } | |
| 76 | |
| 77 if (!render_frame_) | |
| 78 return; | |
| 79 | |
| 80 ImeEventGuard guard(render_frame_->GetRenderWidget()); | |
| 81 std::vector<blink::WebCompositionUnderline> underlines; | |
| 82 for (const auto& underline : ui_underlines) { | |
| 83 blink::WebCompositionUnderline blink_underline( | |
| 84 underline.start_offset, underline.end_offset, underline.color, | |
| 85 underline.thick, underline.background_color); | |
| 86 underlines.push_back(blink_underline); | |
| 87 } | |
| 88 | |
| 89 render_frame_->GetWebFrame()->SetCompositionFromExistingText(start, end, | |
| 90 underlines); | |
| 91 } | |
| 92 | |
| 93 void FrameInputHandlerImpl::ExtendSelectionAndDelete(int32_t before, | |
| 94 int32_t after) { | |
| 95 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 96 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExtendSelectionAndDelete, | |
| 97 this, before, after)); | |
| 98 return; | |
| 99 } | |
| 100 if (!render_frame_) | |
| 101 return; | |
| 102 render_frame_->GetWebFrame()->ExtendSelectionAndDelete(before, after); | |
| 103 } | |
| 104 | |
| 105 void FrameInputHandlerImpl::DeleteSurroundingText(int32_t before, | |
| 106 int32_t after) { | |
| 107 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 108 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::DeleteSurroundingText, | |
| 109 this, before, after)); | |
| 110 return; | |
| 111 } | |
| 112 if (!render_frame_) | |
| 113 return; | |
| 114 render_frame_->GetWebFrame()->DeleteSurroundingText(before, after); | |
| 115 } | |
| 116 | |
| 117 void FrameInputHandlerImpl::DeleteSurroundingTextInCodePoints(int32_t before, | |
| 118 int32_t after) { | |
| 119 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 120 RunOnMainThread( | |
| 121 base::Bind(&FrameInputHandlerImpl::DeleteSurroundingTextInCodePoints, | |
| 122 this, before, after)); | |
| 123 return; | |
| 124 } | |
| 125 if (!render_frame_) | |
| 126 return; | |
| 127 render_frame_->GetWebFrame()->DeleteSurroundingTextInCodePoints(before, | |
| 128 after); | |
| 129 } | |
| 130 | |
| 131 void FrameInputHandlerImpl::SetEditableSelectionOffsets(int32_t start, | |
| 132 int32_t end) { | |
| 133 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 134 RunOnMainThread(base::Bind( | |
| 135 &FrameInputHandlerImpl::SetEditableSelectionOffsets, this, start, end)); | |
| 136 return; | |
| 137 } | |
| 138 if (!render_frame_) | |
| 139 return; | |
| 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()) { | |
| 147 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteEditCommand, this, | |
| 148 command, value)); | |
| 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() { | |
| 165 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
| 166 this, "Undo", UpdateState::kNone)); | |
| 167 } | |
| 168 | |
| 169 void FrameInputHandlerImpl::Redo() { | |
| 170 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
| 171 this, "Redo", UpdateState::kNone)); | |
| 172 } | |
| 173 | |
| 174 void FrameInputHandlerImpl::Cut() { | |
| 175 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
| 176 this, "Cut", UpdateState::kIsSelectingRange)); | |
| 177 } | |
| 178 | |
| 179 void FrameInputHandlerImpl::Copy() { | |
| 180 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
| 181 this, "Copy", UpdateState::kIsSelectingRange)); | |
| 182 } | |
| 183 | |
| 184 void FrameInputHandlerImpl::CopyToFindPboard() { | |
| 185 #if defined(OS_MACOSX) | |
| 186 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 187 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::CopyToFindPboard, this)); | |
| 188 return; | |
| 189 } | |
| 190 if (!render_frame_) | |
| 191 return; | |
| 192 render_frame_->OnCopyToFindPboard(); | |
| 193 #endif | |
| 194 } | |
| 195 | |
| 196 void FrameInputHandlerImpl::Paste() { | |
| 197 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
| 198 this, "Paste", UpdateState::kIsPasting)); | |
| 199 } | |
| 200 | |
| 201 void FrameInputHandlerImpl::PasteAndMatchStyle() { | |
| 202 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
| 203 this, "PasteAndMatchStyle", | |
| 204 UpdateState::kIsPasting)); | |
| 205 } | |
| 206 | |
| 207 void FrameInputHandlerImpl::Replace(const base::string16& word) { | |
| 208 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 209 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::Replace, this, word)); | |
| 210 return; | |
| 211 } | |
| 212 if (!render_frame_) | |
| 213 return; | |
| 214 blink::WebLocalFrame* frame = render_frame_->GetWebFrame(); | |
| 215 if (frame->HasSelection()) | |
| 216 frame->SelectWordAroundCaret(); | |
| 217 frame->ReplaceSelection(blink::WebString::FromUTF16(word)); | |
| 218 render_frame_->SyncSelectionIfRequired(true); | |
| 219 } | |
| 220 | |
| 221 void FrameInputHandlerImpl::ReplaceMisspelling(const base::string16& word) { | |
| 222 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 223 RunOnMainThread( | |
| 224 base::Bind(&FrameInputHandlerImpl::ReplaceMisspelling, this, word)); | |
| 225 return; | |
| 226 } | |
| 227 if (!render_frame_) | |
| 228 return; | |
| 229 blink::WebLocalFrame* frame = render_frame_->GetWebFrame(); | |
| 230 if (!frame->HasSelection()) | |
| 231 return; | |
| 232 frame->ReplaceMisspelledRange(blink::WebString::FromUTF16(word)); | |
| 233 } | |
| 234 | |
| 235 void FrameInputHandlerImpl::Delete() { | |
| 236 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
| 237 this, "Delete", UpdateState::kNone)); | |
| 238 } | |
| 239 | |
| 240 void FrameInputHandlerImpl::SelectAll() { | |
| 241 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
| 242 this, "SelectAll", | |
| 243 UpdateState::kIsSelectingRange)); | |
| 244 } | |
| 245 | |
| 246 void FrameInputHandlerImpl::CollapseSelection() { | |
| 247 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 248 RunOnMainThread( | |
| 249 base::Bind(&FrameInputHandlerImpl::CollapseSelection, this)); | |
| 250 return; | |
| 251 } | |
| 252 | |
| 253 if (!render_frame_) | |
| 254 return; | |
| 255 const blink::WebRange& range = | |
| 256 render_frame_->GetRenderWidget()->GetWebWidget()->CaretOrSelectionRange(); | |
| 257 if (range.IsNull()) | |
| 258 return; | |
| 259 | |
| 260 HandlingState handling_state(render_frame_.get(), | |
| 261 UpdateState::kIsSelectingRange); | |
| 262 render_frame_->GetWebFrame()->SelectRange( | |
| 263 blink::WebRange(range.EndOffset(), 0)); | |
| 264 } | |
| 265 | |
| 266 void FrameInputHandlerImpl::SelectRange(const gfx::Point& base, | |
| 267 const gfx::Point& extent) { | |
| 268 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 269 // TODO(dtapuska): This event should be coalesced. Chrome IPC used | |
| 270 // and ack scheme for this. We should be able to clobber them in the | |
| 271 // main thread event queue. | |
| 272 RunOnMainThread( | |
| 273 base::Bind(&FrameInputHandlerImpl::SelectRange, this, base, extent)); | |
| 274 return; | |
| 275 } | |
| 276 | |
| 277 if (!render_frame_) | |
| 278 return; | |
| 279 RenderViewImpl* render_view = render_frame_->render_view(); | |
| 280 HandlingState handling_state(render_frame_.get(), | |
| 281 UpdateState::kIsSelectingRange); | |
| 282 render_frame_->GetWebFrame()->SelectRange( | |
| 283 render_view->ConvertWindowPointToViewport(base), | |
| 284 render_view->ConvertWindowPointToViewport(extent)); | |
| 285 } | |
| 286 | |
| 287 void FrameInputHandlerImpl::AdjustSelectionByCharacterOffset(int32_t start, | |
| 288 int32_t end) { | |
| 289 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 290 RunOnMainThread( | |
| 291 base::Bind(&FrameInputHandlerImpl::AdjustSelectionByCharacterOffset, | |
| 292 this, start, end)); | |
| 293 return; | |
| 294 } | |
| 295 | |
| 296 if (!render_frame_) | |
| 297 return; | |
| 298 blink::WebRange range = | |
| 299 render_frame_->GetRenderWidget()->GetWebWidget()->CaretOrSelectionRange(); | |
| 300 if (range.IsNull()) | |
| 301 return; | |
| 302 | |
| 303 // Sanity checks to disallow empty and out of range selections. | |
| 304 if (start - end > range.length() || range.StartOffset() + start < 0) | |
| 305 return; | |
| 306 | |
| 307 HandlingState handling_state(render_frame_.get(), | |
| 308 UpdateState::kIsSelectingRange); | |
| 309 // A negative adjust amount moves the selection towards the beginning of | |
| 310 // the document, a positive amount moves the selection towards the end of | |
| 311 // the document. | |
| 312 render_frame_->GetWebFrame()->SelectRange( | |
| 313 blink::WebRange(range.StartOffset() + start, | |
| 314 range.length() + end - start), | |
| 315 blink::WebLocalFrame::kPreserveHandleVisibility); | |
| 316 } | |
| 317 | |
| 318 void FrameInputHandlerImpl::MoveRangeSelectionExtent(const gfx::Point& extent) { | |
| 319 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
| 320 // TODO(dtapuska): This event should be coalesced. Chrome IPC used | |
| 321 // and ack scheme for this. We should be able to clobber them in the | |
| 322 // main thread event queue. | |
| 323 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::MoveRangeSelectionExtent, | |
| 324 this, extent)); | |
| 325 return; | |
| 326 } | |
| 327 | |
| 328 if (!render_frame_) | |
| 329 return; | |
| 330 HandlingState handling_state(render_frame_.get(), | |
| 331 UpdateState::kIsSelectingRange); | |
| 332 render_frame_->GetWebFrame()->MoveRangeSelectionExtent( | |
| 333 render_frame_->render_view()->ConvertWindowPointToViewport(extent)); | |
| 334 } | |
| 335 | |
| 336 void FrameInputHandlerImpl::ExecuteCommandOnMainThread( | |
| 337 const std::string& command, | |
| 338 UpdateState update_state) { | |
| 339 if (!render_frame_) | |
| 340 return; | |
| 341 | |
| 342 HandlingState handling_state(render_frame_.get(), update_state); | |
| 343 render_frame_->GetWebFrame()->ExecuteCommand( | |
| 344 blink::WebString::FromUTF8(command)); | |
| 345 } | |
| 346 | |
| 347 void FrameInputHandlerImpl::BindOnCompositor( | |
| 348 mojom::FrameInputHandlerRequest request) { | |
| 349 BindNow(std::move(request)); | |
| 350 } | |
| 351 | |
| 352 void FrameInputHandlerImpl::BindNow(mojom::FrameInputHandlerRequest request) { | |
| 353 binding_.Bind(std::move(request)); | |
| 354 | |
| 355 // This will Release the ref-counted AddRef that was added in the constructor. | |
| 356 binding_.set_connection_error_handler( | |
| 357 base::Bind(&FrameInputHandlerImpl::Release, this)); | |
| 358 } | |
| 359 | |
| 360 FrameInputHandlerImpl::HandlingState::HandlingState( | |
| 361 RenderFrameImpl* render_frame, | |
| 362 UpdateState state) | |
| 363 : render_frame_(render_frame), | |
| 364 original_select_range_value_(render_frame->handling_select_range()), | |
| 365 original_pasting_value_(render_frame->IsPasting()) { | |
| 366 switch (state) { | |
| 367 case UpdateState::kIsPasting: | |
| 368 render_frame->set_is_pasting(true); | |
| 369 case UpdateState::kIsSelectingRange: | |
| 370 render_frame->set_handling_select_range(true); | |
| 371 break; | |
| 372 case UpdateState::kNone: | |
| 373 break; | |
| 374 } | |
| 375 } | |
| 376 | |
| 377 FrameInputHandlerImpl::HandlingState::~HandlingState() { | |
| 378 render_frame_->set_handling_select_range(original_select_range_value_); | |
| 379 render_frame_->set_is_pasting(original_pasting_value_); | |
| 380 } | |
| 381 | |
| 382 } // namespace content | |
| OLD | NEW |