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 |