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 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(); | |
43 } | |
44 | |
45 FrameInputHandlerImpl::~FrameInputHandlerImpl() {} | |
46 | |
47 // static | |
48 void FrameInputHandlerImpl::CreateMojoService( | |
49 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 or RenderFrame | |
55 // is destructed. | |
56 new FrameInputHandlerImpl(render_frame, std::move(request)); | |
57 } | |
58 | |
59 void FrameInputHandlerImpl::RunOnMainThread(const base::Closure& closure) { | |
60 if (input_event_queue_) { | |
61 input_event_queue_->QueueClosure(closure); | |
62 } else { | |
63 closure.Run(); | |
64 } | |
65 } | |
66 | |
67 void FrameInputHandlerImpl::SetCompositionFromExistingText( | |
68 int32_t start, | |
69 int32_t end, | |
70 const std::vector<ui::CompositionUnderline>& ui_underlines) { | |
71 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
72 RunOnMainThread( | |
73 base::Bind(&FrameInputHandlerImpl::SetCompositionFromExistingText, this, | |
dcheng
2017/05/19 14:59:33
It's not clear to me if we should be binding as a
dtapuska
2017/05/23 16:01:19
So this object is destroyed on the connection hand
| |
74 start, end, ui_underlines)); | |
75 return; | |
76 } | |
77 | |
78 ImeEventGuard guard(GetRenderFrame()->GetRenderWidget()); | |
79 std::vector<blink::WebCompositionUnderline> underlines; | |
80 for (const auto& underline : ui_underlines) { | |
81 blink::WebCompositionUnderline blink_underline( | |
82 underline.start_offset, underline.end_offset, underline.color, | |
83 underline.thick, underline.background_color); | |
84 underlines.push_back(blink_underline); | |
85 } | |
86 | |
87 GetRenderFrame()->GetWebFrame()->SetCompositionFromExistingText(start, end, | |
88 underlines); | |
89 } | |
90 | |
91 void FrameInputHandlerImpl::ExtendSelectionAndDelete(int32_t before, | |
92 int32_t after) { | |
93 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
94 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExtendSelectionAndDelete, | |
95 this, before, after)); | |
96 return; | |
97 } | |
98 GetRenderFrame()->GetWebFrame()->ExtendSelectionAndDelete(before, after); | |
99 } | |
100 | |
101 void FrameInputHandlerImpl::DeleteSurroundingText(int32_t before, | |
102 int32_t after) { | |
103 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
104 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::DeleteSurroundingText, | |
105 this, before, after)); | |
106 return; | |
107 } | |
108 GetRenderFrame()->GetWebFrame()->DeleteSurroundingText(before, after); | |
109 } | |
110 | |
111 void FrameInputHandlerImpl::DeleteSurroundingTextInCodePoints(int32_t before, | |
112 int32_t after) { | |
113 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
114 RunOnMainThread( | |
115 base::Bind(&FrameInputHandlerImpl::DeleteSurroundingTextInCodePoints, | |
116 this, before, after)); | |
117 return; | |
118 } | |
119 GetRenderFrame()->GetWebFrame()->DeleteSurroundingTextInCodePoints(before, | |
120 after); | |
121 } | |
122 | |
123 void FrameInputHandlerImpl::SetEditableSelectionOffsets(int32_t start, | |
124 int32_t end) { | |
125 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
126 RunOnMainThread(base::Bind( | |
127 &FrameInputHandlerImpl::SetEditableSelectionOffsets, this, start, end)); | |
128 return; | |
129 } | |
130 GetRenderFrame()->GetWebFrame()->SetEditableSelectionOffsets(start, end); | |
131 } | |
132 | |
133 void FrameInputHandlerImpl::ExecuteEditCommand( | |
134 const std::string& command, | |
135 const base::Optional<base::string16>& value) { | |
136 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
137 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteEditCommand, this, | |
138 command, value)); | |
139 return; | |
140 } | |
141 if (value) { | |
142 GetRenderFrame()->GetWebFrame()->ExecuteCommand( | |
143 blink::WebString::FromUTF8(command), | |
144 blink::WebString::FromUTF16(value.value())); | |
145 return; | |
146 } | |
147 | |
148 GetRenderFrame()->GetWebFrame()->ExecuteCommand( | |
149 blink::WebString::FromUTF8(command)); | |
150 } | |
151 | |
152 void FrameInputHandlerImpl::Undo() { | |
153 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
154 this, "Undo", UpdateState::kNone)); | |
155 } | |
156 | |
157 void FrameInputHandlerImpl::Redo() { | |
158 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
159 this, "Redo", UpdateState::kNone)); | |
160 } | |
161 | |
162 void FrameInputHandlerImpl::Cut() { | |
163 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
164 this, "Cut", UpdateState::kIsSelectingRange)); | |
165 } | |
166 | |
167 void FrameInputHandlerImpl::Copy() { | |
168 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
169 this, "Copy", UpdateState::kIsSelectingRange)); | |
170 } | |
171 | |
172 void FrameInputHandlerImpl::CopyToFindPboard() { | |
173 #if defined(OS_MACOSX) | |
174 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
175 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::CopyToFindPboard, this)); | |
176 return; | |
177 } | |
178 GetRenderFrame()->OnCopyToFindPboard(); | |
179 #endif | |
180 } | |
181 | |
182 void FrameInputHandlerImpl::Paste() { | |
183 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
184 this, "Paste", UpdateState::kIsPasting)); | |
185 } | |
186 | |
187 void FrameInputHandlerImpl::PasteAndMatchStyle() { | |
188 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
189 this, "PasteAndMatchStyle", | |
190 UpdateState::kIsPasting)); | |
191 } | |
192 | |
193 void FrameInputHandlerImpl::Replace(const base::string16& word) { | |
194 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
195 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::Replace, this, word)); | |
196 return; | |
197 } | |
198 blink::WebLocalFrame* frame = GetRenderFrame()->GetWebFrame(); | |
199 if (frame->HasSelection()) | |
200 frame->SelectWordAroundCaret(); | |
201 frame->ReplaceSelection(blink::WebString::FromUTF16(word)); | |
202 GetRenderFrame()->SyncSelectionIfRequired(); | |
203 } | |
204 | |
205 void FrameInputHandlerImpl::ReplaceMisspelling(const base::string16& word) { | |
206 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
207 RunOnMainThread( | |
208 base::Bind(&FrameInputHandlerImpl::ReplaceMisspelling, this, word)); | |
209 return; | |
210 } | |
211 blink::WebLocalFrame* frame = GetRenderFrame()->GetWebFrame(); | |
212 if (!frame->HasSelection()) | |
213 return; | |
214 frame->ReplaceMisspelledRange(blink::WebString::FromUTF16(word)); | |
215 } | |
216 | |
217 void FrameInputHandlerImpl::Delete() { | |
218 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
219 this, "Delete", UpdateState::kNone)); | |
220 } | |
221 | |
222 void FrameInputHandlerImpl::SelectAll() { | |
223 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::ExecuteCommandOnMainThread, | |
224 this, "SelectAll", | |
225 UpdateState::kIsSelectingRange)); | |
226 } | |
227 | |
228 void FrameInputHandlerImpl::CollapseSelection() { | |
229 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
230 RunOnMainThread( | |
231 base::Bind(&FrameInputHandlerImpl::CollapseSelection, this)); | |
232 return; | |
233 } | |
234 | |
235 const blink::WebRange& range = GetRenderFrame() | |
236 ->GetRenderWidget() | |
237 ->GetWebWidget() | |
238 ->CaretOrSelectionRange(); | |
239 if (range.IsNull()) | |
240 return; | |
241 | |
242 HandlingState handling_state(GetRenderFrame(), | |
243 UpdateState::kIsSelectingRange); | |
244 GetRenderFrame()->GetWebFrame()->SelectRange( | |
245 blink::WebRange(range.EndOffset(), 0)); | |
246 } | |
247 | |
248 void FrameInputHandlerImpl::SelectRange(const gfx::Point& base, | |
249 const gfx::Point& extent) { | |
250 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
251 // TODO(dtapuska): This event should be coalesced. Chrome IPC used | |
252 // and ack scheme for this. We should be able to clobber them in the | |
253 // main thread event queue. | |
254 RunOnMainThread( | |
255 base::Bind(&FrameInputHandlerImpl::SelectRange, this, base, extent)); | |
256 return; | |
257 } | |
258 | |
259 RenderFrameImpl* render_frame = GetRenderFrame(); | |
260 RenderViewImpl* render_view = render_frame->render_view(); | |
261 HandlingState handling_state(render_frame, UpdateState::kIsSelectingRange); | |
262 render_frame->GetWebFrame()->SelectRange( | |
263 render_view->ConvertWindowPointToViewport(base), | |
264 render_view->ConvertWindowPointToViewport(extent)); | |
265 } | |
266 | |
267 void FrameInputHandlerImpl::AdjustSelectionByCharacterOffset(int32_t start, | |
268 int32_t end) { | |
269 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
270 RunOnMainThread( | |
271 base::Bind(&FrameInputHandlerImpl::AdjustSelectionByCharacterOffset, | |
272 this, start, end)); | |
273 return; | |
274 } | |
275 | |
276 blink::WebRange range = GetRenderFrame() | |
277 ->GetRenderWidget() | |
278 ->GetWebWidget() | |
279 ->CaretOrSelectionRange(); | |
280 if (range.IsNull()) | |
281 return; | |
282 | |
283 // Sanity checks to disallow empty and out of range selections. | |
284 if (start - end > range.length() || range.StartOffset() + start < 0) | |
285 return; | |
286 | |
287 HandlingState handling_state(GetRenderFrame(), | |
288 UpdateState::kIsSelectingRange); | |
289 // A negative adjust amount moves the selection towards the beginning of | |
290 // the document, a positive amount moves the selection towards the end of | |
291 // the document. | |
292 GetRenderFrame()->GetWebFrame()->SelectRange( | |
293 blink::WebRange(range.StartOffset() + start, | |
294 range.length() + end - start), | |
295 blink::WebLocalFrame::kPreserveHandleVisibility); | |
296 } | |
297 | |
298 void FrameInputHandlerImpl::MoveRangeSelectionExtent(const gfx::Point& extent) { | |
299 if (!main_thread_task_runner_->BelongsToCurrentThread()) { | |
300 // TODO(dtapuska): This event should be coalesced. Chrome IPC used | |
301 // and ack scheme for this. We should be able to clobber them in the | |
302 // main thread event queue. | |
303 RunOnMainThread(base::Bind(&FrameInputHandlerImpl::MoveRangeSelectionExtent, | |
304 this, extent)); | |
305 return; | |
306 } | |
307 | |
308 HandlingState handling_state(GetRenderFrame(), | |
309 UpdateState::kIsSelectingRange); | |
310 GetRenderFrame()->GetWebFrame()->MoveRangeSelectionExtent( | |
311 GetRenderFrame()->render_view()->ConvertWindowPointToViewport(extent)); | |
312 } | |
313 | |
314 void FrameInputHandlerImpl::ExecuteCommandOnMainThread( | |
315 const std::string& command, | |
316 UpdateState update_state) { | |
317 HandlingState handling_state(GetRenderFrame(), update_state); | |
318 GetRenderFrame()->GetWebFrame()->ExecuteCommand( | |
319 blink::WebString::FromUTF8(command)); | |
320 } | |
321 | |
322 void FrameInputHandlerImpl::BindOnCompositor( | |
323 mojom::FrameInputHandlerRequest request) { | |
324 BindNow(std::move(request)); | |
325 } | |
326 | |
327 void FrameInputHandlerImpl::BindNow(mojom::FrameInputHandlerRequest request) { | |
328 binding_.Bind(std::move(request)); | |
329 | |
330 // This will Release the ref-counted AddRef that was added in the constructor. | |
331 binding_.set_connection_error_handler( | |
332 base::Bind(&FrameInputHandlerImpl::Release, this)); | |
333 } | |
334 | |
335 RenderFrameImpl* FrameInputHandlerImpl::GetRenderFrame() { | |
336 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); | |
337 return render_frame_; | |
338 } | |
339 | |
340 FrameInputHandlerImpl::HandlingState::HandlingState( | |
341 RenderFrameImpl* render_frame, | |
342 UpdateState state) | |
343 : render_frame_(render_frame), | |
344 original_select_range_value_(render_frame->handling_select_range()), | |
345 original_pasting_value_(render_frame->IsPasting()) { | |
346 switch (state) { | |
347 case UpdateState::kIsPasting: | |
348 render_frame->set_is_pasting(true); | |
349 case UpdateState::kIsSelectingRange: | |
350 render_frame->set_handling_select_range(true); | |
351 break; | |
352 case UpdateState::kNone: | |
353 break; | |
354 } | |
355 } | |
356 | |
357 FrameInputHandlerImpl::HandlingState::~HandlingState() { | |
358 render_frame_->set_handling_select_range(original_select_range_value_); | |
359 render_frame_->set_is_pasting(original_pasting_value_); | |
360 } | |
361 | |
362 } // namespace content | |
OLD | NEW |