OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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 "chrome/browser/renderer_host/render_widget_host.h" | |
6 | |
7 #include "base/auto_reset.h" | |
8 #include "base/command_line.h" | |
9 #include "base/message_loop.h" | |
10 #include "base/metrics/histogram.h" | |
11 #include "chrome/browser/accessibility/browser_accessibility_state.h" | |
12 #include "chrome/browser/metrics/user_metrics.h" | |
13 #include "chrome/browser/renderer_host/backing_store.h" | |
14 #include "chrome/browser/renderer_host/backing_store_manager.h" | |
15 #include "chrome/browser/renderer_host/render_process_host.h" | |
16 #include "chrome/browser/renderer_host/render_widget_helper.h" | |
17 #include "chrome/browser/renderer_host/render_widget_host_view.h" | |
18 #include "chrome/common/chrome_switches.h" | |
19 #include "chrome/common/result_codes.h" | |
20 #include "chrome/common/native_web_keyboard_event.h" | |
21 #include "chrome/common/notification_service.h" | |
22 #include "chrome/common/render_messages.h" | |
23 #include "chrome/common/render_messages_params.h" | |
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderli
ne.h" | |
25 #include "ui/base/keycodes/keyboard_codes.h" | |
26 #include "webkit/glue/webcursor.h" | |
27 #include "webkit/plugins/npapi/webplugin.h" | |
28 | |
29 #if defined(TOOLKIT_VIEWS) | |
30 #include "views/view.h" | |
31 #endif | |
32 | |
33 #if defined (OS_MACOSX) | |
34 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" | |
35 #include "third_party/WebKit/Source/WebKit/chromium/public/mac/WebScreenInfoFact
ory.h" | |
36 #endif | |
37 | |
38 using base::Time; | |
39 using base::TimeDelta; | |
40 using base::TimeTicks; | |
41 | |
42 using WebKit::WebInputEvent; | |
43 using WebKit::WebKeyboardEvent; | |
44 using WebKit::WebMouseEvent; | |
45 using WebKit::WebMouseWheelEvent; | |
46 using WebKit::WebTextDirection; | |
47 | |
48 #if defined (OS_MACOSX) | |
49 using WebKit::WebScreenInfo; | |
50 using WebKit::WebScreenInfoFactory; | |
51 #endif | |
52 | |
53 // How long to (synchronously) wait for the renderer to respond with a | |
54 // PaintRect message, when our backing-store is invalid, before giving up and | |
55 // returning a null or incorrectly sized backing-store from GetBackingStore. | |
56 // This timeout impacts the "choppiness" of our window resize perf. | |
57 static const int kPaintMsgTimeoutMS = 40; | |
58 | |
59 // How long to wait before we consider a renderer hung. | |
60 static const int kHungRendererDelayMs = 20000; | |
61 | |
62 // The maximum time between wheel messages while coalescing. This trades off | |
63 // smoothness of scrolling with a risk of falling behind the events, resulting | |
64 // in trailing scrolls after the user ends their input. | |
65 static const int kMaxTimeBetweenWheelMessagesMs = 250; | |
66 | |
67 /////////////////////////////////////////////////////////////////////////////// | |
68 // RenderWidgetHost | |
69 | |
70 RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process, | |
71 int routing_id) | |
72 : renderer_initialized_(false), | |
73 renderer_accessible_(false), | |
74 view_(NULL), | |
75 process_(process), | |
76 routing_id_(routing_id), | |
77 is_loading_(false), | |
78 is_hidden_(false), | |
79 is_accelerated_compositing_active_(false), | |
80 repaint_ack_pending_(false), | |
81 resize_ack_pending_(false), | |
82 mouse_move_pending_(false), | |
83 mouse_wheel_pending_(false), | |
84 needs_repainting_on_restore_(false), | |
85 is_unresponsive_(false), | |
86 in_get_backing_store_(false), | |
87 view_being_painted_(false), | |
88 ignore_input_events_(false), | |
89 text_direction_updated_(false), | |
90 text_direction_(WebKit::WebTextDirectionLeftToRight), | |
91 text_direction_canceled_(false), | |
92 suppress_next_char_events_(false) { | |
93 if (routing_id_ == MSG_ROUTING_NONE) | |
94 routing_id_ = process_->GetNextRoutingID(); | |
95 | |
96 process_->Attach(this, routing_id_); | |
97 // Because the widget initializes as is_hidden_ == false, | |
98 // tell the process host that we're alive. | |
99 process_->WidgetRestored(); | |
100 | |
101 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
102 switches::kForceRendererAccessibility) || | |
103 BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) { | |
104 EnableRendererAccessibility(); | |
105 } | |
106 } | |
107 | |
108 RenderWidgetHost::~RenderWidgetHost() { | |
109 // Clear our current or cached backing store if either remains. | |
110 BackingStoreManager::RemoveBackingStore(this); | |
111 | |
112 process_->Release(routing_id_); | |
113 } | |
114 | |
115 gfx::NativeViewId RenderWidgetHost::GetNativeViewId() { | |
116 if (view_) | |
117 return gfx::IdFromNativeView(view_->GetNativeView()); | |
118 return 0; | |
119 } | |
120 | |
121 bool RenderWidgetHost::PreHandleKeyboardEvent( | |
122 const NativeWebKeyboardEvent& event, | |
123 bool* is_keyboard_shortcut) { | |
124 return false; | |
125 } | |
126 | |
127 void RenderWidgetHost::Init() { | |
128 DCHECK(process_->HasConnection()); | |
129 | |
130 renderer_initialized_ = true; | |
131 | |
132 // Send the ack along with the information on placement. | |
133 Send(new ViewMsg_CreatingNew_ACK(routing_id_, GetNativeViewId())); | |
134 WasResized(); | |
135 } | |
136 | |
137 void RenderWidgetHost::Shutdown() { | |
138 if (process_->HasConnection()) { | |
139 // Tell the renderer object to close. | |
140 process_->ReportExpectingClose(routing_id_); | |
141 bool rv = Send(new ViewMsg_Close(routing_id_)); | |
142 DCHECK(rv); | |
143 } | |
144 | |
145 Destroy(); | |
146 } | |
147 | |
148 bool RenderWidgetHost::IsRenderView() const { | |
149 return false; | |
150 } | |
151 | |
152 bool RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) { | |
153 bool handled = true; | |
154 bool msg_is_ok = true; | |
155 IPC_BEGIN_MESSAGE_MAP_EX(RenderWidgetHost, msg, msg_is_ok) | |
156 IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewReady, OnMsgRenderViewReady) | |
157 IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewGone, OnMsgRenderViewGone) | |
158 IPC_MESSAGE_HANDLER(ViewHostMsg_Close, OnMsgClose) | |
159 IPC_MESSAGE_HANDLER(ViewHostMsg_RequestMove, OnMsgRequestMove) | |
160 IPC_MESSAGE_HANDLER(ViewHostMsg_PaintAtSize_ACK, OnMsgPaintAtSizeAck) | |
161 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnMsgUpdateRect) | |
162 IPC_MESSAGE_HANDLER(ViewHostMsg_HandleInputEvent_ACK, OnMsgInputEventAck) | |
163 IPC_MESSAGE_HANDLER(ViewHostMsg_Focus, OnMsgFocus) | |
164 IPC_MESSAGE_HANDLER(ViewHostMsg_Blur, OnMsgBlur) | |
165 IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnMsgSetCursor) | |
166 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeUpdateTextInputState, | |
167 OnMsgImeUpdateTextInputState) | |
168 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition, | |
169 OnMsgImeCancelComposition) | |
170 IPC_MESSAGE_HANDLER(ViewHostMsg_DidActivateAcceleratedCompositing, | |
171 OnMsgDidActivateAcceleratedCompositing) | |
172 #if defined(OS_MACOSX) | |
173 IPC_MESSAGE_HANDLER(ViewHostMsg_GetScreenInfo, OnMsgGetScreenInfo) | |
174 IPC_MESSAGE_HANDLER(ViewHostMsg_GetWindowRect, OnMsgGetWindowRect) | |
175 IPC_MESSAGE_HANDLER(ViewHostMsg_GetRootWindowRect, OnMsgGetRootWindowRect) | |
176 IPC_MESSAGE_HANDLER(ViewHostMsg_PluginFocusChanged, | |
177 OnMsgPluginFocusChanged) | |
178 IPC_MESSAGE_HANDLER(ViewHostMsg_StartPluginIme, | |
179 OnMsgStartPluginIme) | |
180 IPC_MESSAGE_HANDLER(ViewHostMsg_AllocateFakePluginWindowHandle, | |
181 OnAllocateFakePluginWindowHandle) | |
182 IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyFakePluginWindowHandle, | |
183 OnDestroyFakePluginWindowHandle) | |
184 IPC_MESSAGE_HANDLER(ViewHostMsg_AcceleratedSurfaceSetIOSurface, | |
185 OnAcceleratedSurfaceSetIOSurface) | |
186 IPC_MESSAGE_HANDLER(ViewHostMsg_AcceleratedSurfaceSetTransportDIB, | |
187 OnAcceleratedSurfaceSetTransportDIB) | |
188 IPC_MESSAGE_HANDLER(ViewHostMsg_AcceleratedSurfaceBuffersSwapped, | |
189 OnAcceleratedSurfaceBuffersSwapped) | |
190 #elif defined(OS_POSIX) | |
191 IPC_MESSAGE_HANDLER(ViewHostMsg_CreatePluginContainer, | |
192 OnMsgCreatePluginContainer) | |
193 IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyPluginContainer, | |
194 OnMsgDestroyPluginContainer) | |
195 #endif | |
196 IPC_MESSAGE_UNHANDLED(handled = false) | |
197 IPC_END_MESSAGE_MAP_EX() | |
198 | |
199 if (!msg_is_ok) { | |
200 // The message de-serialization failed. Kill the renderer process. | |
201 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH")); | |
202 process()->ReceivedBadMessage(); | |
203 } | |
204 return handled; | |
205 } | |
206 | |
207 bool RenderWidgetHost::Send(IPC::Message* msg) { | |
208 return process_->Send(msg); | |
209 } | |
210 | |
211 void RenderWidgetHost::WasHidden() { | |
212 is_hidden_ = true; | |
213 | |
214 // Don't bother reporting hung state when we aren't the active tab. | |
215 StopHangMonitorTimeout(); | |
216 | |
217 // If we have a renderer, then inform it that we are being hidden so it can | |
218 // reduce its resource utilization. | |
219 Send(new ViewMsg_WasHidden(routing_id_)); | |
220 | |
221 // TODO(darin): what about constrained windows? it doesn't look like they | |
222 // see a message when their parent is hidden. maybe there is something more | |
223 // generic we can do at the TabContents API level instead of relying on | |
224 // Windows messages. | |
225 | |
226 // Tell the RenderProcessHost we were hidden. | |
227 process_->WidgetHidden(); | |
228 | |
229 bool is_visible = false; | |
230 NotificationService::current()->Notify( | |
231 NotificationType::RENDER_WIDGET_VISIBILITY_CHANGED, | |
232 Source<RenderWidgetHost>(this), | |
233 Details<bool>(&is_visible)); | |
234 } | |
235 | |
236 void RenderWidgetHost::WasRestored() { | |
237 // When we create the widget, it is created as *not* hidden. | |
238 if (!is_hidden_) | |
239 return; | |
240 is_hidden_ = false; | |
241 | |
242 BackingStore* backing_store = BackingStoreManager::Lookup(this); | |
243 // If we already have a backing store for this widget, then we don't need to | |
244 // repaint on restore _unless_ we know that our backing store is invalid. | |
245 // When accelerated compositing is on, we must always repaint, even when | |
246 // the backing store exists. | |
247 bool needs_repainting; | |
248 if (needs_repainting_on_restore_ || !backing_store || | |
249 is_accelerated_compositing_active()) { | |
250 needs_repainting = true; | |
251 needs_repainting_on_restore_ = false; | |
252 } else { | |
253 needs_repainting = false; | |
254 } | |
255 Send(new ViewMsg_WasRestored(routing_id_, needs_repainting)); | |
256 | |
257 process_->WidgetRestored(); | |
258 | |
259 bool is_visible = true; | |
260 NotificationService::current()->Notify( | |
261 NotificationType::RENDER_WIDGET_VISIBILITY_CHANGED, | |
262 Source<RenderWidgetHost>(this), | |
263 Details<bool>(&is_visible)); | |
264 | |
265 // It's possible for our size to be out of sync with the renderer. The | |
266 // following is one case that leads to this: | |
267 // 1. WasResized -> Send ViewMsg_Resize to render | |
268 // 2. WasResized -> do nothing as resize_ack_pending_ is true | |
269 // 3. WasHidden | |
270 // 4. OnMsgUpdateRect from (1) processed. Does NOT invoke WasResized as view | |
271 // is hidden. Now renderer/browser out of sync with what they think size | |
272 // is. | |
273 // By invoking WasResized the renderer is updated as necessary. WasResized | |
274 // does nothing if the sizes are already in sync. | |
275 // | |
276 // TODO: ideally ViewMsg_WasRestored would take a size. This way, the renderer | |
277 // could handle both the restore and resize at once. This isn't that big a | |
278 // deal as RenderWidget::WasRestored delays updating, so that the resize from | |
279 // WasResized is usually processed before the renderer is painted. | |
280 WasResized(); | |
281 } | |
282 | |
283 void RenderWidgetHost::WasResized() { | |
284 if (resize_ack_pending_ || !process_->HasConnection() || !view_ || | |
285 !renderer_initialized_) { | |
286 return; | |
287 } | |
288 | |
289 #if !defined(OS_MACOSX) | |
290 gfx::Size new_size = view_->GetViewBounds().size(); | |
291 #else | |
292 // When UI scaling is enabled on OS X, allocate a smaller bitmap and | |
293 // pixel-scale it up. | |
294 // TODO(thakis): Use pixel size on mac and set UI scale in renderer. | |
295 // http://crbug.com/31960 | |
296 gfx::Size new_size(view_->GetViewCocoaBounds().size()); | |
297 #endif | |
298 gfx::Rect reserved_rect = view_->reserved_contents_rect(); | |
299 | |
300 // Avoid asking the RenderWidget to resize to its current size, since it | |
301 // won't send us a PaintRect message in that case, unless reserved area is | |
302 // changed, but even in this case PaintRect message won't be sent. | |
303 if (new_size == current_size_ && reserved_rect == current_reserved_rect_) | |
304 return; | |
305 | |
306 if (in_flight_size_ != gfx::Size() && new_size == in_flight_size_ && | |
307 in_flight_reserved_rect_ == reserved_rect) { | |
308 return; | |
309 } | |
310 | |
311 // We don't expect to receive an ACK when the requested size is empty or | |
312 // only reserved area is changed. | |
313 resize_ack_pending_ = !new_size.IsEmpty() && new_size != current_size_; | |
314 | |
315 if (!Send(new ViewMsg_Resize(routing_id_, new_size, reserved_rect))) { | |
316 resize_ack_pending_ = false; | |
317 } else { | |
318 if (resize_ack_pending_) { | |
319 in_flight_size_ = new_size; | |
320 in_flight_reserved_rect_ = reserved_rect; | |
321 } else { | |
322 // Message was sent successfully, but we do not expect to receive an ACK, | |
323 // so update current values right away. | |
324 current_size_ = new_size; | |
325 // TODO(alekseys): send a message from renderer to ack a reserved rect | |
326 // changes only. | |
327 current_reserved_rect_ = reserved_rect; | |
328 } | |
329 } | |
330 } | |
331 | |
332 void RenderWidgetHost::GotFocus() { | |
333 Focus(); | |
334 } | |
335 | |
336 void RenderWidgetHost::Focus() { | |
337 Send(new ViewMsg_SetFocus(routing_id_, true)); | |
338 } | |
339 | |
340 void RenderWidgetHost::Blur() { | |
341 Send(new ViewMsg_SetFocus(routing_id_, false)); | |
342 } | |
343 | |
344 void RenderWidgetHost::LostCapture() { | |
345 Send(new ViewMsg_MouseCaptureLost(routing_id_)); | |
346 } | |
347 | |
348 void RenderWidgetHost::ViewDestroyed() { | |
349 // TODO(evanm): tracking this may no longer be necessary; | |
350 // eliminate this function if so. | |
351 view_ = NULL; | |
352 } | |
353 | |
354 void RenderWidgetHost::SetIsLoading(bool is_loading) { | |
355 is_loading_ = is_loading; | |
356 if (!view_) | |
357 return; | |
358 view_->SetIsLoading(is_loading); | |
359 } | |
360 | |
361 void RenderWidgetHost::PaintAtSize(TransportDIB::Handle dib_handle, | |
362 int tag, | |
363 const gfx::Size& page_size, | |
364 const gfx::Size& desired_size) { | |
365 // Ask the renderer to create a bitmap regardless of whether it's | |
366 // hidden, being resized, redrawn, etc. It resizes the web widget | |
367 // to the page_size and then scales it to the desired_size. | |
368 Send(new ViewMsg_PaintAtSize(routing_id_, dib_handle, tag, | |
369 page_size, desired_size)); | |
370 } | |
371 | |
372 BackingStore* RenderWidgetHost::GetBackingStore(bool force_create) { | |
373 // We should not be asked to paint while we are hidden. If we are hidden, | |
374 // then it means that our consumer failed to call WasRestored. If we're not | |
375 // force creating the backing store, it's OK since we can feel free to give | |
376 // out our cached one if we have it. | |
377 DCHECK(!is_hidden_ || !force_create) << | |
378 "GetBackingStore called while hidden!"; | |
379 | |
380 // We should never be called recursively; this can theoretically lead to | |
381 // infinite recursion and almost certainly leads to lower performance. | |
382 DCHECK(!in_get_backing_store_) << "GetBackingStore called recursively!"; | |
383 AutoReset<bool> auto_reset_in_get_backing_store(&in_get_backing_store_, true); | |
384 | |
385 // We might have a cached backing store that we can reuse! | |
386 BackingStore* backing_store = | |
387 BackingStoreManager::GetBackingStore(this, current_size_); | |
388 if (!force_create) | |
389 return backing_store; | |
390 | |
391 // If we fail to find a backing store in the cache, send out a request | |
392 // to the renderer to paint the view if required. | |
393 if (!backing_store && !repaint_ack_pending_ && !resize_ack_pending_ && | |
394 !view_being_painted_) { | |
395 repaint_start_time_ = TimeTicks::Now(); | |
396 repaint_ack_pending_ = true; | |
397 Send(new ViewMsg_Repaint(routing_id_, current_size_)); | |
398 } | |
399 | |
400 // When we have asked the RenderWidget to resize, and we are still waiting on | |
401 // a response, block for a little while to see if we can't get a response | |
402 // before returning the old (incorrectly sized) backing store. | |
403 if (resize_ack_pending_ || !backing_store) { | |
404 IPC::Message msg; | |
405 TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS); | |
406 if (process_->WaitForUpdateMsg(routing_id_, max_delay, &msg)) { | |
407 OnMessageReceived(msg); | |
408 backing_store = BackingStoreManager::GetBackingStore(this, current_size_); | |
409 } | |
410 } | |
411 | |
412 return backing_store; | |
413 } | |
414 | |
415 BackingStore* RenderWidgetHost::AllocBackingStore(const gfx::Size& size) { | |
416 if (!view_) | |
417 return NULL; | |
418 return view_->AllocBackingStore(size); | |
419 } | |
420 | |
421 void RenderWidgetHost::DonePaintingToBackingStore() { | |
422 Send(new ViewMsg_UpdateRect_ACK(routing_id())); | |
423 } | |
424 | |
425 void RenderWidgetHost::ScheduleComposite() { | |
426 if (is_hidden_ || !is_accelerated_compositing_active_) { | |
427 return; | |
428 } | |
429 | |
430 // Send out a request to the renderer to paint the view if required. | |
431 if (!repaint_ack_pending_ && !resize_ack_pending_ && !view_being_painted_) { | |
432 repaint_start_time_ = TimeTicks::Now(); | |
433 repaint_ack_pending_ = true; | |
434 Send(new ViewMsg_Repaint(routing_id_, current_size_)); | |
435 } | |
436 | |
437 // When we have asked the RenderWidget to resize, and we are still waiting on | |
438 // a response, block for a little while to see if we can't get a response. | |
439 // We always block on response because we do not have a backing store. | |
440 IPC::Message msg; | |
441 TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS); | |
442 if (process_->WaitForUpdateMsg(routing_id_, max_delay, &msg)) | |
443 OnMessageReceived(msg); | |
444 } | |
445 | |
446 void RenderWidgetHost::StartHangMonitorTimeout(TimeDelta delay) { | |
447 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
448 switches::kDisableHangMonitor)) { | |
449 return; | |
450 } | |
451 | |
452 // If we already have a timer that will expire at or before the given delay, | |
453 // then we have nothing more to do now. If we have set our end time to null | |
454 // by calling StopHangMonitorTimeout, though, we will need to restart the | |
455 // timer. | |
456 if (hung_renderer_timer_.IsRunning() && | |
457 hung_renderer_timer_.GetCurrentDelay() <= delay && | |
458 !time_when_considered_hung_.is_null()) { | |
459 return; | |
460 } | |
461 | |
462 // Either the timer is not yet running, or we need to adjust the timer to | |
463 // fire sooner. | |
464 time_when_considered_hung_ = Time::Now() + delay; | |
465 hung_renderer_timer_.Stop(); | |
466 hung_renderer_timer_.Start(delay, this, | |
467 &RenderWidgetHost::CheckRendererIsUnresponsive); | |
468 } | |
469 | |
470 void RenderWidgetHost::RestartHangMonitorTimeout() { | |
471 // Setting to null will cause StartHangMonitorTimeout to restart the timer. | |
472 time_when_considered_hung_ = Time(); | |
473 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kHungRendererDelayMs)); | |
474 } | |
475 | |
476 void RenderWidgetHost::StopHangMonitorTimeout() { | |
477 time_when_considered_hung_ = Time(); | |
478 RendererIsResponsive(); | |
479 | |
480 // We do not bother to stop the hung_renderer_timer_ here in case it will be | |
481 // started again shortly, which happens to be the common use case. | |
482 } | |
483 | |
484 void RenderWidgetHost::SystemThemeChanged() { | |
485 Send(new ViewMsg_ThemeChanged(routing_id_)); | |
486 } | |
487 | |
488 void RenderWidgetHost::ForwardMouseEvent(const WebMouseEvent& mouse_event) { | |
489 if (ignore_input_events_ || process_->ignore_input_events()) | |
490 return; | |
491 | |
492 // Avoid spamming the renderer with mouse move events. It is important | |
493 // to note that WM_MOUSEMOVE events are anyways synthetic, but since our | |
494 // thread is able to rapidly consume WM_MOUSEMOVE events, we may get way | |
495 // more WM_MOUSEMOVE events than we wish to send to the renderer. | |
496 if (mouse_event.type == WebInputEvent::MouseMove) { | |
497 if (mouse_move_pending_) { | |
498 next_mouse_move_.reset(new WebMouseEvent(mouse_event)); | |
499 return; | |
500 } | |
501 mouse_move_pending_ = true; | |
502 } else if (mouse_event.type == WebInputEvent::MouseDown) { | |
503 OnUserGesture(); | |
504 } | |
505 | |
506 ForwardInputEvent(mouse_event, sizeof(WebMouseEvent), false); | |
507 } | |
508 | |
509 void RenderWidgetHost::OnMouseActivate() { | |
510 } | |
511 | |
512 void RenderWidgetHost::ForwardWheelEvent( | |
513 const WebMouseWheelEvent& wheel_event) { | |
514 if (ignore_input_events_ || process_->ignore_input_events()) | |
515 return; | |
516 | |
517 // If there's already a mouse wheel event waiting to be sent to the renderer, | |
518 // add the new deltas to that event. Not doing so (e.g., by dropping the old | |
519 // event, as for mouse moves) results in very slow scrolling on the Mac (on | |
520 // which many, very small wheel events are sent). | |
521 if (mouse_wheel_pending_) { | |
522 if (coalesced_mouse_wheel_events_.empty() || | |
523 coalesced_mouse_wheel_events_.back().modifiers | |
524 != wheel_event.modifiers || | |
525 coalesced_mouse_wheel_events_.back().scrollByPage | |
526 != wheel_event.scrollByPage) { | |
527 coalesced_mouse_wheel_events_.push_back(wheel_event); | |
528 } else { | |
529 WebMouseWheelEvent* last_wheel_event = | |
530 &coalesced_mouse_wheel_events_.back(); | |
531 last_wheel_event->deltaX += wheel_event.deltaX; | |
532 last_wheel_event->deltaY += wheel_event.deltaY; | |
533 DCHECK_GE(wheel_event.timeStampSeconds, | |
534 last_wheel_event->timeStampSeconds); | |
535 last_wheel_event->timeStampSeconds = wheel_event.timeStampSeconds; | |
536 } | |
537 return; | |
538 } | |
539 mouse_wheel_pending_ = true; | |
540 | |
541 HISTOGRAM_COUNTS_100("MPArch.RWH_WheelQueueSize", | |
542 coalesced_mouse_wheel_events_.size()); | |
543 | |
544 ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent), false); | |
545 } | |
546 | |
547 void RenderWidgetHost::ForwardKeyboardEvent( | |
548 const NativeWebKeyboardEvent& key_event) { | |
549 if (ignore_input_events_ || process_->ignore_input_events()) | |
550 return; | |
551 | |
552 if (key_event.type == WebKeyboardEvent::Char && | |
553 (key_event.windowsKeyCode == ui::VKEY_RETURN || | |
554 key_event.windowsKeyCode == ui::VKEY_SPACE)) { | |
555 OnUserGesture(); | |
556 } | |
557 | |
558 // Double check the type to make sure caller hasn't sent us nonsense that | |
559 // will mess up our key queue. | |
560 if (WebInputEvent::isKeyboardEventType(key_event.type)) { | |
561 if (suppress_next_char_events_) { | |
562 // If preceding RawKeyDown event was handled by the browser, then we need | |
563 // suppress all Char events generated by it. Please note that, one | |
564 // RawKeyDown event may generate multiple Char events, so we can't reset | |
565 // |suppress_next_char_events_| until we get a KeyUp or a RawKeyDown. | |
566 if (key_event.type == WebKeyboardEvent::Char) | |
567 return; | |
568 // We get a KeyUp or a RawKeyDown event. | |
569 suppress_next_char_events_ = false; | |
570 } | |
571 | |
572 bool is_keyboard_shortcut = false; | |
573 // Only pre-handle the key event if it's not handled by the input method. | |
574 if (!key_event.skip_in_browser) { | |
575 // We need to set |suppress_next_char_events_| to true if | |
576 // PreHandleKeyboardEvent() returns true, but |this| may already be | |
577 // destroyed at that time. So set |suppress_next_char_events_| true here, | |
578 // then revert it afterwards when necessary. | |
579 if (key_event.type == WebKeyboardEvent::RawKeyDown) | |
580 suppress_next_char_events_ = true; | |
581 | |
582 // Tab switching/closing accelerators aren't sent to the renderer to avoid | |
583 // a hung/malicious renderer from interfering. | |
584 if (PreHandleKeyboardEvent(key_event, &is_keyboard_shortcut)) | |
585 return; | |
586 | |
587 if (key_event.type == WebKeyboardEvent::RawKeyDown) | |
588 suppress_next_char_events_ = false; | |
589 } | |
590 | |
591 // Don't add this key to the queue if we have no way to send the message... | |
592 if (!process_->HasConnection()) | |
593 return; | |
594 | |
595 // Put all WebKeyboardEvent objects in a queue since we can't trust the | |
596 // renderer and we need to give something to the UnhandledInputEvent | |
597 // handler. | |
598 key_queue_.push_back(key_event); | |
599 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); | |
600 | |
601 // Only forward the non-native portions of our event. | |
602 ForwardInputEvent(key_event, sizeof(WebKeyboardEvent), | |
603 is_keyboard_shortcut); | |
604 } | |
605 } | |
606 | |
607 void RenderWidgetHost::ForwardInputEvent(const WebInputEvent& input_event, | |
608 int event_size, | |
609 bool is_keyboard_shortcut) { | |
610 if (!process_->HasConnection()) | |
611 return; | |
612 | |
613 DCHECK(!process_->ignore_input_events()); | |
614 | |
615 IPC::Message* message = new ViewMsg_HandleInputEvent(routing_id_); | |
616 message->WriteData( | |
617 reinterpret_cast<const char*>(&input_event), event_size); | |
618 // |is_keyboard_shortcut| only makes sense for RawKeyDown events. | |
619 if (input_event.type == WebInputEvent::RawKeyDown) | |
620 message->WriteBool(is_keyboard_shortcut); | |
621 input_event_start_time_ = TimeTicks::Now(); | |
622 Send(message); | |
623 | |
624 // Any non-wheel input event cancels pending wheel events. | |
625 if (input_event.type != WebInputEvent::MouseWheel) | |
626 coalesced_mouse_wheel_events_.clear(); | |
627 | |
628 // Any input event cancels a pending mouse move event. Note that | |
629 // |next_mouse_move_| possibly owns |input_event|, so don't use |input_event| | |
630 // after this line. | |
631 next_mouse_move_.reset(); | |
632 | |
633 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kHungRendererDelayMs)); | |
634 } | |
635 | |
636 void RenderWidgetHost::ForwardEditCommand(const std::string& name, | |
637 const std::string& value) { | |
638 // We don't need an implementation of this function here since the | |
639 // only place we use this is for the case of dropdown menus and other | |
640 // edge cases for which edit commands don't make sense. | |
641 } | |
642 | |
643 void RenderWidgetHost::ForwardEditCommandsForNextKeyEvent( | |
644 const EditCommands& edit_commands) { | |
645 // We don't need an implementation of this function here since this message is | |
646 // only handled by RenderView. | |
647 } | |
648 | |
649 #if defined(TOUCH_UI) | |
650 void RenderWidgetHost::ForwardTouchEvent( | |
651 const WebKit::WebTouchEvent& touch_event) { | |
652 ForwardInputEvent(touch_event, sizeof(WebKit::WebTouchEvent), false); | |
653 } | |
654 #endif | |
655 | |
656 void RenderWidgetHost::RendererExited(base::TerminationStatus status, | |
657 int exit_code) { | |
658 // Clearing this flag causes us to re-create the renderer when recovering | |
659 // from a crashed renderer. | |
660 renderer_initialized_ = false; | |
661 | |
662 // Must reset these to ensure that mouse move/wheel events work with a new | |
663 // renderer. | |
664 mouse_move_pending_ = false; | |
665 next_mouse_move_.reset(); | |
666 mouse_wheel_pending_ = false; | |
667 coalesced_mouse_wheel_events_.clear(); | |
668 | |
669 // Must reset these to ensure that keyboard events work with a new renderer. | |
670 key_queue_.clear(); | |
671 suppress_next_char_events_ = false; | |
672 | |
673 // Reset some fields in preparation for recovering from a crash. | |
674 resize_ack_pending_ = false; | |
675 repaint_ack_pending_ = false; | |
676 | |
677 in_flight_size_.SetSize(0, 0); | |
678 in_flight_reserved_rect_.SetRect(0, 0, 0, 0); | |
679 current_size_.SetSize(0, 0); | |
680 current_reserved_rect_.SetRect(0, 0, 0, 0); | |
681 is_hidden_ = false; | |
682 is_accelerated_compositing_active_ = false; | |
683 | |
684 if (view_) { | |
685 view_->RenderViewGone(status, exit_code); | |
686 view_ = NULL; // The View should be deleted by RenderViewGone. | |
687 } | |
688 | |
689 BackingStoreManager::RemoveBackingStore(this); | |
690 } | |
691 | |
692 void RenderWidgetHost::UpdateTextDirection(WebTextDirection direction) { | |
693 text_direction_updated_ = true; | |
694 text_direction_ = direction; | |
695 } | |
696 | |
697 void RenderWidgetHost::CancelUpdateTextDirection() { | |
698 if (text_direction_updated_) | |
699 text_direction_canceled_ = true; | |
700 } | |
701 | |
702 void RenderWidgetHost::NotifyTextDirection() { | |
703 if (text_direction_updated_) { | |
704 if (!text_direction_canceled_) | |
705 Send(new ViewMsg_SetTextDirection(routing_id(), text_direction_)); | |
706 text_direction_updated_ = false; | |
707 text_direction_canceled_ = false; | |
708 } | |
709 } | |
710 | |
711 void RenderWidgetHost::SetInputMethodActive(bool activate) { | |
712 Send(new ViewMsg_SetInputMethodActive(routing_id(), activate)); | |
713 } | |
714 | |
715 void RenderWidgetHost::ImeSetComposition( | |
716 const string16& text, | |
717 const std::vector<WebKit::WebCompositionUnderline>& underlines, | |
718 int selection_start, | |
719 int selection_end) { | |
720 Send(new ViewMsg_ImeSetComposition( | |
721 routing_id(), text, underlines, selection_start, selection_end)); | |
722 } | |
723 | |
724 void RenderWidgetHost::ImeConfirmComposition(const string16& text) { | |
725 Send(new ViewMsg_ImeConfirmComposition(routing_id(), text)); | |
726 } | |
727 | |
728 void RenderWidgetHost::ImeConfirmComposition() { | |
729 Send(new ViewMsg_ImeConfirmComposition(routing_id(), string16())); | |
730 } | |
731 | |
732 void RenderWidgetHost::ImeCancelComposition() { | |
733 Send(new ViewMsg_ImeSetComposition(routing_id(), string16(), | |
734 std::vector<WebKit::WebCompositionUnderline>(), 0, 0)); | |
735 } | |
736 | |
737 void RenderWidgetHost::SetActive(bool active) { | |
738 Send(new ViewMsg_SetActive(routing_id(), active)); | |
739 } | |
740 | |
741 void RenderWidgetHost::Destroy() { | |
742 NotificationService::current()->Notify( | |
743 NotificationType::RENDER_WIDGET_HOST_DESTROYED, | |
744 Source<RenderWidgetHost>(this), | |
745 NotificationService::NoDetails()); | |
746 | |
747 // Tell the view to die. | |
748 // Note that in the process of the view shutting down, it can call a ton | |
749 // of other messages on us. So if you do any other deinitialization here, | |
750 // do it after this call to view_->Destroy(). | |
751 if (view_) | |
752 view_->Destroy(); | |
753 | |
754 delete this; | |
755 } | |
756 | |
757 void RenderWidgetHost::CheckRendererIsUnresponsive() { | |
758 // If we received a call to StopHangMonitorTimeout. | |
759 if (time_when_considered_hung_.is_null()) | |
760 return; | |
761 | |
762 // If we have not waited long enough, then wait some more. | |
763 Time now = Time::Now(); | |
764 if (now < time_when_considered_hung_) { | |
765 StartHangMonitorTimeout(time_when_considered_hung_ - now); | |
766 return; | |
767 } | |
768 | |
769 // OK, looks like we have a hung renderer! | |
770 NotificationService::current()->Notify( | |
771 NotificationType::RENDERER_PROCESS_HANG, | |
772 Source<RenderWidgetHost>(this), | |
773 NotificationService::NoDetails()); | |
774 is_unresponsive_ = true; | |
775 NotifyRendererUnresponsive(); | |
776 } | |
777 | |
778 void RenderWidgetHost::RendererIsResponsive() { | |
779 if (is_unresponsive_) { | |
780 is_unresponsive_ = false; | |
781 NotifyRendererResponsive(); | |
782 } | |
783 } | |
784 | |
785 void RenderWidgetHost::OnMsgRenderViewReady() { | |
786 WasResized(); | |
787 } | |
788 | |
789 void RenderWidgetHost::OnMsgRenderViewGone(int status, int exit_code) { | |
790 // TODO(evanm): This synchronously ends up calling "delete this". | |
791 // Is that really what we want in response to this message? I'm matching | |
792 // previous behavior of the code here. | |
793 Destroy(); | |
794 } | |
795 | |
796 void RenderWidgetHost::OnMsgClose() { | |
797 Shutdown(); | |
798 } | |
799 | |
800 void RenderWidgetHost::OnMsgRequestMove(const gfx::Rect& pos) { | |
801 // Note that we ignore the position. | |
802 if (view_) { | |
803 view_->SetSize(pos.size()); | |
804 Send(new ViewMsg_Move_ACK(routing_id_)); | |
805 } | |
806 } | |
807 | |
808 void RenderWidgetHost::OnMsgPaintAtSizeAck(int tag, const gfx::Size& size) { | |
809 PaintAtSizeAckDetails details = {tag, size}; | |
810 gfx::Size size_details = size; | |
811 NotificationService::current()->Notify( | |
812 NotificationType::RENDER_WIDGET_HOST_DID_RECEIVE_PAINT_AT_SIZE_ACK, | |
813 Source<RenderWidgetHost>(this), | |
814 Details<PaintAtSizeAckDetails>(&details)); | |
815 } | |
816 | |
817 void RenderWidgetHost::OnMsgUpdateRect( | |
818 const ViewHostMsg_UpdateRect_Params& params) { | |
819 TimeTicks paint_start = TimeTicks::Now(); | |
820 | |
821 NotificationService::current()->Notify( | |
822 NotificationType::RENDER_WIDGET_HOST_WILL_PAINT, | |
823 Source<RenderWidgetHost>(this), | |
824 NotificationService::NoDetails()); | |
825 | |
826 // Update our knowledge of the RenderWidget's size. | |
827 current_size_ = params.view_size; | |
828 // Update our knowledge of the RenderWidget's scroll offset. | |
829 last_scroll_offset_ = params.scroll_offset; | |
830 | |
831 bool is_resize_ack = | |
832 ViewHostMsg_UpdateRect_Flags::is_resize_ack(params.flags); | |
833 | |
834 // resize_ack_pending_ needs to be cleared before we call DidPaintRect, since | |
835 // that will end up reaching GetBackingStore. | |
836 if (is_resize_ack) { | |
837 DCHECK(resize_ack_pending_); | |
838 resize_ack_pending_ = false; | |
839 in_flight_size_.SetSize(0, 0); | |
840 in_flight_reserved_rect_.SetRect(0, 0, 0, 0); | |
841 // Update our knowledge of the RenderWidget's resizer rect. | |
842 // ViewMsg_Resize is acknowledged only when view size is actually changed, | |
843 // otherwise current_reserved_rect_ is updated immediately after sending | |
844 // ViewMsg_Resize to the RenderWidget and can be clobbered by | |
845 // OnMsgUpdateRect called for a paint that was initiated before the resize | |
846 // message was sent. | |
847 current_reserved_rect_ = params.resizer_rect; | |
848 } | |
849 | |
850 bool is_repaint_ack = | |
851 ViewHostMsg_UpdateRect_Flags::is_repaint_ack(params.flags); | |
852 if (is_repaint_ack) { | |
853 repaint_ack_pending_ = false; | |
854 TimeDelta delta = TimeTicks::Now() - repaint_start_time_; | |
855 UMA_HISTOGRAM_TIMES("MPArch.RWH_RepaintDelta", delta); | |
856 } | |
857 | |
858 DCHECK(!params.bitmap_rect.IsEmpty()); | |
859 DCHECK(!params.view_size.IsEmpty()); | |
860 | |
861 if (!is_accelerated_compositing_active_) { | |
862 const size_t size = params.bitmap_rect.height() * | |
863 params.bitmap_rect.width() * 4; | |
864 TransportDIB* dib = process_->GetTransportDIB(params.bitmap); | |
865 | |
866 // If gpu process does painting, scroll_rect and copy_rects are always empty | |
867 // and backing store is never used. | |
868 if (dib) { | |
869 if (dib->size() < size) { | |
870 DLOG(WARNING) << "Transport DIB too small for given rectangle"; | |
871 UserMetrics::RecordAction(UserMetricsAction( | |
872 "BadMessageTerminate_RWH1")); | |
873 process()->ReceivedBadMessage(); | |
874 } else { | |
875 // Scroll the backing store. | |
876 if (!params.scroll_rect.IsEmpty()) { | |
877 ScrollBackingStoreRect(params.dx, params.dy, | |
878 params.scroll_rect, | |
879 params.view_size); | |
880 } | |
881 | |
882 // Paint the backing store. This will update it with the | |
883 // renderer-supplied bits. The view will read out of the backing store | |
884 // later to actually draw to the screen. | |
885 PaintBackingStoreRect(params.bitmap, params.bitmap_rect, | |
886 params.copy_rects, params.view_size); | |
887 } | |
888 } | |
889 } | |
890 | |
891 // ACK early so we can prefetch the next PaintRect if there is a next one. | |
892 // This must be done AFTER we're done painting with the bitmap supplied by the | |
893 // renderer. This ACK is a signal to the renderer that the backing store can | |
894 // be re-used, so the bitmap may be invalid after this call. | |
895 Send(new ViewMsg_UpdateRect_ACK(routing_id_)); | |
896 | |
897 // We don't need to update the view if the view is hidden. We must do this | |
898 // early return after the ACK is sent, however, or the renderer will not send | |
899 // us more data. | |
900 if (is_hidden_) | |
901 return; | |
902 | |
903 // Now paint the view. Watch out: it might be destroyed already. | |
904 if (view_) { | |
905 view_->MovePluginWindows(params.plugin_window_moves); | |
906 // The view_ pointer could be destroyed in the context of MovePluginWindows | |
907 // which attempts to move the plugin windows and in the process could | |
908 // dispatch other window messages which could cause the view to be | |
909 // destroyed. | |
910 if (view_ && !is_accelerated_compositing_active_) { | |
911 view_being_painted_ = true; | |
912 view_->DidUpdateBackingStore(params.scroll_rect, params.dx, params.dy, | |
913 params.copy_rects); | |
914 view_being_painted_ = false; | |
915 } | |
916 } | |
917 | |
918 NotificationService::current()->Notify( | |
919 NotificationType::RENDER_WIDGET_HOST_DID_PAINT, | |
920 Source<RenderWidgetHost>(this), | |
921 NotificationService::NoDetails()); | |
922 | |
923 // If we got a resize ack, then perhaps we have another resize to send? | |
924 if (is_resize_ack && view_) { | |
925 // WasResized checks the current size and sends the resize update only | |
926 // when something was actually changed. | |
927 WasResized(); | |
928 } | |
929 | |
930 NotificationService::current()->Notify( | |
931 NotificationType::RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, | |
932 Source<RenderWidgetHost>(this), | |
933 NotificationService::NoDetails()); | |
934 | |
935 // Log the time delta for processing a paint message. | |
936 TimeDelta delta = TimeTicks::Now() - paint_start; | |
937 UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgUpdateRect", delta); | |
938 } | |
939 | |
940 void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) { | |
941 // Log the time delta for processing an input event. | |
942 TimeDelta delta = TimeTicks::Now() - input_event_start_time_; | |
943 UMA_HISTOGRAM_TIMES("MPArch.RWH_InputEventDelta", delta); | |
944 | |
945 // Cancel pending hung renderer checks since the renderer is responsive. | |
946 StopHangMonitorTimeout(); | |
947 | |
948 void* iter = NULL; | |
949 int type = 0; | |
950 if (!message.ReadInt(&iter, &type) || (type < WebInputEvent::Undefined)) { | |
951 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH2")); | |
952 process()->ReceivedBadMessage(); | |
953 } else if (type == WebInputEvent::MouseMove) { | |
954 mouse_move_pending_ = false; | |
955 | |
956 // now, we can send the next mouse move event | |
957 if (next_mouse_move_.get()) { | |
958 DCHECK(next_mouse_move_->type == WebInputEvent::MouseMove); | |
959 ForwardMouseEvent(*next_mouse_move_); | |
960 } | |
961 } else if (type == WebInputEvent::MouseWheel) { | |
962 ProcessWheelAck(); | |
963 } else if (WebInputEvent::isKeyboardEventType(type)) { | |
964 bool processed = false; | |
965 if (!message.ReadBool(&iter, &processed)) { | |
966 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH3")); | |
967 process()->ReceivedBadMessage(); | |
968 } | |
969 | |
970 ProcessKeyboardEventAck(type, processed); | |
971 } | |
972 // This is used only for testing. | |
973 NotificationService::current()->Notify( | |
974 NotificationType::RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK, | |
975 Source<RenderWidgetHost>(this), | |
976 Details<int>(&type)); | |
977 } | |
978 | |
979 void RenderWidgetHost::ProcessWheelAck() { | |
980 mouse_wheel_pending_ = false; | |
981 | |
982 // Now send the next (coalesced) mouse wheel event. | |
983 if (!coalesced_mouse_wheel_events_.empty()) { | |
984 WebMouseWheelEvent next_wheel_event = | |
985 coalesced_mouse_wheel_events_.front(); | |
986 coalesced_mouse_wheel_events_.pop_front(); | |
987 ForwardWheelEvent(next_wheel_event); | |
988 } | |
989 } | |
990 | |
991 void RenderWidgetHost::OnMsgFocus() { | |
992 // Only RenderViewHost can deal with that message. | |
993 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH4")); | |
994 process()->ReceivedBadMessage(); | |
995 } | |
996 | |
997 void RenderWidgetHost::OnMsgBlur() { | |
998 // Only RenderViewHost can deal with that message. | |
999 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH5")); | |
1000 process()->ReceivedBadMessage(); | |
1001 } | |
1002 | |
1003 void RenderWidgetHost::OnMsgSetCursor(const WebCursor& cursor) { | |
1004 if (!view_) { | |
1005 return; | |
1006 } | |
1007 view_->UpdateCursor(cursor); | |
1008 } | |
1009 | |
1010 void RenderWidgetHost::OnMsgImeUpdateTextInputState( | |
1011 WebKit::WebTextInputType type, | |
1012 const gfx::Rect& caret_rect) { | |
1013 if (view_) | |
1014 view_->ImeUpdateTextInputState(type, caret_rect); | |
1015 } | |
1016 | |
1017 void RenderWidgetHost::OnMsgImeCancelComposition() { | |
1018 if (view_) | |
1019 view_->ImeCancelComposition(); | |
1020 } | |
1021 | |
1022 void RenderWidgetHost::OnMsgDidActivateAcceleratedCompositing(bool activated) { | |
1023 #if defined(OS_MACOSX) | |
1024 bool old_state = is_accelerated_compositing_active_; | |
1025 #endif | |
1026 is_accelerated_compositing_active_ = activated; | |
1027 #if defined(OS_MACOSX) | |
1028 if (old_state != is_accelerated_compositing_active_ && view_) | |
1029 view_->GpuRenderingStateDidChange(); | |
1030 #elif defined(OS_WIN) | |
1031 if (view_) | |
1032 view_->ShowCompositorHostWindow(is_accelerated_compositing_active_); | |
1033 #elif defined(TOOLKIT_USES_GTK) | |
1034 if (view_) | |
1035 view_->AcceleratedCompositingActivated(activated); | |
1036 #endif | |
1037 } | |
1038 | |
1039 #if defined(OS_MACOSX) | |
1040 | |
1041 void RenderWidgetHost::OnMsgGetScreenInfo(gfx::NativeViewId view, | |
1042 WebScreenInfo* results) { | |
1043 gfx::NativeView native_view = view_ ? view_->GetNativeView() : NULL; | |
1044 *results = WebScreenInfoFactory::screenInfo(native_view); | |
1045 } | |
1046 | |
1047 void RenderWidgetHost::OnMsgGetWindowRect(gfx::NativeViewId window_id, | |
1048 gfx::Rect* results) { | |
1049 if (view_) { | |
1050 *results = view_->GetViewBounds(); | |
1051 } | |
1052 } | |
1053 | |
1054 void RenderWidgetHost::OnMsgGetRootWindowRect(gfx::NativeViewId window_id, | |
1055 gfx::Rect* results) { | |
1056 if (view_) { | |
1057 *results = view_->GetRootWindowRect(); | |
1058 } | |
1059 } | |
1060 | |
1061 void RenderWidgetHost::OnMsgPluginFocusChanged(bool focused, int plugin_id) { | |
1062 if (view_) | |
1063 view_->PluginFocusChanged(focused, plugin_id); | |
1064 } | |
1065 | |
1066 void RenderWidgetHost::OnMsgStartPluginIme() { | |
1067 if (view_) | |
1068 view_->StartPluginIme(); | |
1069 } | |
1070 | |
1071 void RenderWidgetHost::OnAllocateFakePluginWindowHandle( | |
1072 bool opaque, | |
1073 bool root, | |
1074 gfx::PluginWindowHandle* id) { | |
1075 // TODO(kbr): similar potential issue here as in OnMsgCreatePluginContainer. | |
1076 // Possibly less of an issue because this is only used for the GPU plugin. | |
1077 if (view_) { | |
1078 *id = view_->AllocateFakePluginWindowHandle(opaque, root); | |
1079 } else { | |
1080 NOTIMPLEMENTED(); | |
1081 } | |
1082 } | |
1083 | |
1084 void RenderWidgetHost::OnDestroyFakePluginWindowHandle( | |
1085 gfx::PluginWindowHandle id) { | |
1086 if (view_) { | |
1087 view_->DestroyFakePluginWindowHandle(id); | |
1088 } else { | |
1089 NOTIMPLEMENTED(); | |
1090 } | |
1091 } | |
1092 | |
1093 void RenderWidgetHost::OnAcceleratedSurfaceSetIOSurface( | |
1094 gfx::PluginWindowHandle window, | |
1095 int32 width, | |
1096 int32 height, | |
1097 uint64 mach_port) { | |
1098 if (view_) { | |
1099 view_->AcceleratedSurfaceSetIOSurface(window, width, height, mach_port); | |
1100 } | |
1101 } | |
1102 | |
1103 void RenderWidgetHost::OnAcceleratedSurfaceSetTransportDIB( | |
1104 gfx::PluginWindowHandle window, | |
1105 int32 width, | |
1106 int32 height, | |
1107 TransportDIB::Handle transport_dib) { | |
1108 if (view_) { | |
1109 view_->AcceleratedSurfaceSetTransportDIB(window, width, height, | |
1110 transport_dib); | |
1111 } | |
1112 } | |
1113 | |
1114 void RenderWidgetHost::OnAcceleratedSurfaceBuffersSwapped( | |
1115 gfx::PluginWindowHandle window, uint64 surface_id) { | |
1116 if (view_) { | |
1117 // This code path could be updated to implement flow control for | |
1118 // updating of accelerated plugins as well. However, if we add support | |
1119 // for composited plugins then this is not necessary. | |
1120 view_->AcceleratedSurfaceBuffersSwapped(window, surface_id, | |
1121 0, 0, 0); | |
1122 } | |
1123 } | |
1124 #elif defined(OS_POSIX) | |
1125 | |
1126 void RenderWidgetHost::OnMsgCreatePluginContainer(gfx::PluginWindowHandle id) { | |
1127 // TODO(piman): view_ can only be NULL with delayed view creation in | |
1128 // extensions (see ExtensionHost::CreateRenderViewSoon). Figure out how to | |
1129 // support plugins in that case. | |
1130 if (view_) { | |
1131 view_->CreatePluginContainer(id); | |
1132 } else { | |
1133 deferred_plugin_handles_.push_back(id); | |
1134 } | |
1135 } | |
1136 | |
1137 void RenderWidgetHost::OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id) { | |
1138 if (view_) { | |
1139 view_->DestroyPluginContainer(id); | |
1140 } else { | |
1141 for (int i = 0; | |
1142 i < static_cast<int>(deferred_plugin_handles_.size()); | |
1143 i++) { | |
1144 if (deferred_plugin_handles_[i] == id) { | |
1145 deferred_plugin_handles_.erase(deferred_plugin_handles_.begin() + i); | |
1146 i--; | |
1147 } | |
1148 } | |
1149 } | |
1150 } | |
1151 #endif | |
1152 | |
1153 void RenderWidgetHost::PaintBackingStoreRect( | |
1154 TransportDIB::Id bitmap, | |
1155 const gfx::Rect& bitmap_rect, | |
1156 const std::vector<gfx::Rect>& copy_rects, | |
1157 const gfx::Size& view_size) { | |
1158 // The view may be destroyed already. | |
1159 if (!view_) | |
1160 return; | |
1161 | |
1162 if (is_hidden_) { | |
1163 // Don't bother updating the backing store when we're hidden. Just mark it | |
1164 // as being totally invalid. This will cause a complete repaint when the | |
1165 // view is restored. | |
1166 needs_repainting_on_restore_ = true; | |
1167 return; | |
1168 } | |
1169 | |
1170 bool needs_full_paint = false; | |
1171 BackingStoreManager::PrepareBackingStore(this, view_size, bitmap, bitmap_rect, | |
1172 copy_rects, &needs_full_paint); | |
1173 if (needs_full_paint) { | |
1174 repaint_start_time_ = TimeTicks::Now(); | |
1175 repaint_ack_pending_ = true; | |
1176 Send(new ViewMsg_Repaint(routing_id_, view_size)); | |
1177 } | |
1178 } | |
1179 | |
1180 void RenderWidgetHost::ScrollBackingStoreRect(int dx, int dy, | |
1181 const gfx::Rect& clip_rect, | |
1182 const gfx::Size& view_size) { | |
1183 if (is_hidden_) { | |
1184 // Don't bother updating the backing store when we're hidden. Just mark it | |
1185 // as being totally invalid. This will cause a complete repaint when the | |
1186 // view is restored. | |
1187 needs_repainting_on_restore_ = true; | |
1188 return; | |
1189 } | |
1190 | |
1191 // TODO(darin): do we need to do something else if our backing store is not | |
1192 // the same size as the advertised view? maybe we just assume there is a | |
1193 // full paint on its way? | |
1194 BackingStore* backing_store = BackingStoreManager::Lookup(this); | |
1195 if (!backing_store || (backing_store->size() != view_size)) | |
1196 return; | |
1197 backing_store->ScrollBackingStore(dx, dy, clip_rect, view_size); | |
1198 } | |
1199 | |
1200 void RenderWidgetHost::ToggleSpellPanel(bool is_currently_visible) { | |
1201 Send(new ViewMsg_ToggleSpellPanel(routing_id(), is_currently_visible)); | |
1202 } | |
1203 | |
1204 void RenderWidgetHost::Replace(const string16& word) { | |
1205 Send(new ViewMsg_Replace(routing_id_, word)); | |
1206 } | |
1207 | |
1208 void RenderWidgetHost::AdvanceToNextMisspelling() { | |
1209 Send(new ViewMsg_AdvanceToNextMisspelling(routing_id_)); | |
1210 } | |
1211 | |
1212 void RenderWidgetHost::EnableRendererAccessibility() { | |
1213 if (renderer_accessible_) | |
1214 return; | |
1215 | |
1216 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
1217 switches::kDisableRendererAccessibility)) { | |
1218 return; | |
1219 } | |
1220 | |
1221 renderer_accessible_ = true; | |
1222 | |
1223 if (process_->HasConnection()) { | |
1224 // Renderer accessibility wasn't enabled on process launch. Enable it now. | |
1225 Send(new ViewMsg_EnableAccessibility(routing_id())); | |
1226 } | |
1227 } | |
1228 | |
1229 void RenderWidgetHost::SetAccessibilityFocus(int acc_obj_id) { | |
1230 Send(new ViewMsg_SetAccessibilityFocus(routing_id(), acc_obj_id)); | |
1231 } | |
1232 | |
1233 void RenderWidgetHost::AccessibilityDoDefaultAction(int acc_obj_id) { | |
1234 Send(new ViewMsg_AccessibilityDoDefaultAction(routing_id(), acc_obj_id)); | |
1235 } | |
1236 | |
1237 void RenderWidgetHost::AccessibilityNotificationsAck() { | |
1238 Send(new ViewMsg_AccessibilityNotifications_ACK(routing_id())); | |
1239 } | |
1240 | |
1241 void RenderWidgetHost::ProcessKeyboardEventAck(int type, bool processed) { | |
1242 if (key_queue_.size() == 0) { | |
1243 LOG(ERROR) << "Got a KeyEvent back from the renderer but we " | |
1244 << "don't seem to have sent it to the renderer!"; | |
1245 } else if (key_queue_.front().type != type) { | |
1246 LOG(ERROR) << "We seem to have a different key type sent from " | |
1247 << "the renderer. (" << key_queue_.front().type << " vs. " | |
1248 << type << "). Ignoring event."; | |
1249 | |
1250 // Something must be wrong. Clear the |key_queue_| and | |
1251 // |suppress_next_char_events_| so that we can resume from the error. | |
1252 key_queue_.clear(); | |
1253 suppress_next_char_events_ = false; | |
1254 } else { | |
1255 NativeWebKeyboardEvent front_item = key_queue_.front(); | |
1256 key_queue_.pop_front(); | |
1257 | |
1258 #if defined(OS_MACOSX) | |
1259 if (!is_hidden_ && view_->PostProcessEventForPluginIme(front_item)) | |
1260 return; | |
1261 #endif | |
1262 | |
1263 // We only send unprocessed key event upwards if we are not hidden, | |
1264 // because the user has moved away from us and no longer expect any effect | |
1265 // of this key event. | |
1266 if (!processed && !is_hidden_ && !front_item.skip_in_browser) { | |
1267 UnhandledKeyboardEvent(front_item); | |
1268 | |
1269 // WARNING: This RenderWidgetHost can be deallocated at this point | |
1270 // (i.e. in the case of Ctrl+W, where the call to | |
1271 // UnhandledKeyboardEvent destroys this RenderWidgetHost). | |
1272 } | |
1273 } | |
1274 } | |
1275 | |
1276 void RenderWidgetHost::ActivateDeferredPluginHandles() { | |
1277 if (view_ == NULL) | |
1278 return; | |
1279 | |
1280 for (int i = 0; i < static_cast<int>(deferred_plugin_handles_.size()); i++) { | |
1281 #if defined(TOOLKIT_USES_GTK) | |
1282 view_->CreatePluginContainer(deferred_plugin_handles_[i]); | |
1283 #endif | |
1284 } | |
1285 | |
1286 deferred_plugin_handles_.clear(); | |
1287 } | |
OLD | NEW |