Disable ContentSettingBubbleModelTest.RPHAllow which is flaky.
[chromium-blink-merge.git] / content / renderer / render_widget.cc
blobb681e5def33c972ab0d4dc026ad28ad3bf359857
1 // Copyright (c) 2012 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.
5 #include "content/renderer/render_widget.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/debug/trace_event.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop.h"
13 #include "base/metrics/histogram.h"
14 #include "base/stl_util.h"
15 #include "base/utf_string_conversions.h"
16 #include "build/build_config.h"
17 #include "cc/base/switches.h"
18 #include "cc/base/thread.h"
19 #include "cc/base/thread_impl.h"
20 #include "cc/output/output_surface.h"
21 #include "cc/trees/layer_tree_host.h"
22 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
23 #include "content/common/input_messages.h"
24 #include "content/common/swapped_out_messages.h"
25 #include "content/common/view_messages.h"
26 #include "content/public/common/content_switches.h"
27 #include "content/renderer/gpu/compositor_output_surface.h"
28 #include "content/renderer/gpu/compositor_software_output_device.h"
29 #include "content/renderer/gpu/input_handler_manager.h"
30 #include "content/renderer/gpu/mailbox_output_surface.h"
31 #include "content/renderer/gpu/render_widget_compositor.h"
32 #include "content/renderer/render_process.h"
33 #include "content/renderer/render_thread_impl.h"
34 #include "content/renderer/renderer_webkitplatformsupport_impl.h"
35 #include "ipc/ipc_sync_message.h"
36 #include "skia/ext/platform_canvas.h"
37 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
38 #include "third_party/WebKit/Source/Platform/chromium/public/WebPoint.h"
39 #include "third_party/WebKit/Source/Platform/chromium/public/WebRect.h"
40 #include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h"
41 #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
42 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
43 #include "third_party/WebKit/Source/WebKit/chromium/public/WebHelperPlugin.h"
44 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPagePopup.h"
45 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h"
46 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenuInfo.h"
47 #include "third_party/WebKit/Source/WebKit/chromium/public/WebRange.h"
48 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h"
49 #include "third_party/skia/include/core/SkShader.h"
50 #include "ui/base/ui_base_switches.h"
51 #include "ui/gfx/rect_conversions.h"
52 #include "ui/gfx/size_conversions.h"
53 #include "ui/gfx/skia_util.h"
54 #include "ui/gl/gl_switches.h"
55 #include "ui/surface/transport_dib.h"
56 #include "webkit/compositor_bindings/web_rendering_stats_impl.h"
57 #include "webkit/glue/webkit_glue.h"
58 #include "webkit/plugins/npapi/webplugin.h"
59 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
61 #if defined(OS_ANDROID)
62 #include "content/renderer/android/synchronous_compositor_output_surface.h"
63 #endif
65 #if defined(OS_POSIX)
66 #include "ipc/ipc_channel_posix.h"
67 #include "third_party/skia/include/core/SkMallocPixelRef.h"
68 #include "third_party/skia/include/core/SkPixelRef.h"
69 #endif // defined(OS_POSIX)
71 #include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h"
73 using WebKit::WebCompositionUnderline;
74 using WebKit::WebCursorInfo;
75 using WebKit::WebGestureEvent;
76 using WebKit::WebInputEvent;
77 using WebKit::WebMouseEvent;
78 using WebKit::WebNavigationPolicy;
79 using WebKit::WebPagePopup;
80 using WebKit::WebPoint;
81 using WebKit::WebPopupMenu;
82 using WebKit::WebPopupMenuInfo;
83 using WebKit::WebPopupType;
84 using WebKit::WebRange;
85 using WebKit::WebRect;
86 using WebKit::WebScreenInfo;
87 using WebKit::WebSize;
88 using WebKit::WebTextDirection;
89 using WebKit::WebTouchEvent;
90 using WebKit::WebVector;
91 using WebKit::WebWidget;
93 namespace {
94 const char* GetEventName(WebInputEvent::Type type) {
95 #define CASE_TYPE(t) case WebInputEvent::t: return #t
96 switch(type) {
97 CASE_TYPE(Undefined);
98 CASE_TYPE(MouseDown);
99 CASE_TYPE(MouseUp);
100 CASE_TYPE(MouseMove);
101 CASE_TYPE(MouseEnter);
102 CASE_TYPE(MouseLeave);
103 CASE_TYPE(ContextMenu);
104 CASE_TYPE(MouseWheel);
105 CASE_TYPE(RawKeyDown);
106 CASE_TYPE(KeyDown);
107 CASE_TYPE(KeyUp);
108 CASE_TYPE(Char);
109 CASE_TYPE(GestureScrollBegin);
110 CASE_TYPE(GestureScrollEnd);
111 CASE_TYPE(GestureScrollUpdate);
112 CASE_TYPE(GestureFlingStart);
113 CASE_TYPE(GestureFlingCancel);
114 CASE_TYPE(GestureTap);
115 CASE_TYPE(GestureTapDown);
116 CASE_TYPE(GestureTapCancel);
117 CASE_TYPE(GestureDoubleTap);
118 CASE_TYPE(GestureTwoFingerTap);
119 CASE_TYPE(GestureLongPress);
120 CASE_TYPE(GestureLongTap);
121 CASE_TYPE(GesturePinchBegin);
122 CASE_TYPE(GesturePinchEnd);
123 CASE_TYPE(GesturePinchUpdate);
124 CASE_TYPE(TouchStart);
125 CASE_TYPE(TouchMove);
126 CASE_TYPE(TouchEnd);
127 CASE_TYPE(TouchCancel);
128 default:
129 // Must include default to let WebKit::WebInputEvent add new event types
130 // before they're added here.
131 DLOG(WARNING) << "Unhandled WebInputEvent type in GetEventName.\n";
132 break;
134 #undef CASE_TYPE
135 return "";
138 namespace content {
140 RenderWidget::RenderWidget(WebKit::WebPopupType popup_type,
141 const WebKit::WebScreenInfo& screen_info,
142 bool swapped_out)
143 : routing_id_(MSG_ROUTING_NONE),
144 surface_id_(0),
145 webwidget_(NULL),
146 opener_id_(MSG_ROUTING_NONE),
147 init_complete_(false),
148 current_paint_buf_(NULL),
149 overdraw_bottom_height_(0.f),
150 next_paint_flags_(0),
151 filtered_time_per_frame_(0.0f),
152 update_reply_pending_(false),
153 auto_resize_mode_(false),
154 need_update_rect_for_auto_resize_(false),
155 using_asynchronous_swapbuffers_(false),
156 num_swapbuffers_complete_pending_(0),
157 did_show_(false),
158 is_hidden_(false),
159 is_fullscreen_(false),
160 needs_repainting_on_restore_(false),
161 has_focus_(false),
162 handling_input_event_(false),
163 handling_ime_event_(false),
164 closing_(false),
165 is_swapped_out_(swapped_out),
166 input_method_is_active_(false),
167 text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
168 can_compose_inline_(true),
169 popup_type_(popup_type),
170 pending_window_rect_count_(0),
171 suppress_next_char_events_(false),
172 is_accelerated_compositing_active_(false),
173 animation_update_pending_(false),
174 invalidation_task_posted_(false),
175 screen_info_(screen_info),
176 device_scale_factor_(screen_info_.deviceScaleFactor),
177 throttle_input_events_(true),
178 is_threaded_compositing_enabled_(false),
179 weak_ptr_factory_(this) {
180 if (!swapped_out)
181 RenderProcess::current()->AddRefProcess();
182 DCHECK(RenderThread::Get());
183 has_disable_gpu_vsync_switch_ = CommandLine::ForCurrentProcess()->HasSwitch(
184 switches::kDisableGpuVsync);
185 is_threaded_compositing_enabled_ =
186 CommandLine::ForCurrentProcess()->HasSwitch(
187 switches::kEnableThreadedCompositing);
190 RenderWidget::~RenderWidget() {
191 DCHECK(!webwidget_) << "Leaking our WebWidget!";
192 STLDeleteElements(&updates_pending_swap_);
193 if (current_paint_buf_) {
194 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
195 current_paint_buf_ = NULL;
197 // If we are swapped out, we have released already.
198 if (!is_swapped_out_)
199 RenderProcess::current()->ReleaseProcess();
202 // static
203 RenderWidget* RenderWidget::Create(int32 opener_id,
204 WebKit::WebPopupType popup_type,
205 const WebKit::WebScreenInfo& screen_info) {
206 DCHECK(opener_id != MSG_ROUTING_NONE);
207 scoped_refptr<RenderWidget> widget(
208 new RenderWidget(popup_type, screen_info, false));
209 if (widget->Init(opener_id)) { // adds reference on success.
210 return widget;
212 return NULL;
215 // static
216 WebWidget* RenderWidget::CreateWebWidget(RenderWidget* render_widget) {
217 switch (render_widget->popup_type_) {
218 case WebKit::WebPopupTypeNone: // Nothing to create.
219 break;
220 case WebKit::WebPopupTypeSelect:
221 case WebKit::WebPopupTypeSuggestion:
222 return WebPopupMenu::create(render_widget);
223 case WebKit::WebPopupTypePage:
224 return WebPagePopup::create(render_widget);
225 case WebKit::WebPopupTypeHelperPlugin:
226 return WebKit::WebHelperPlugin::create(render_widget);
227 default:
228 NOTREACHED();
230 return NULL;
233 bool RenderWidget::Init(int32 opener_id) {
234 return DoInit(opener_id,
235 RenderWidget::CreateWebWidget(this),
236 new ViewHostMsg_CreateWidget(opener_id, popup_type_,
237 &routing_id_, &surface_id_));
240 bool RenderWidget::DoInit(int32 opener_id,
241 WebWidget* web_widget,
242 IPC::SyncMessage* create_widget_message) {
243 DCHECK(!webwidget_);
245 if (opener_id != MSG_ROUTING_NONE)
246 opener_id_ = opener_id;
248 webwidget_ = web_widget;
250 bool result = RenderThread::Get()->Send(create_widget_message);
251 if (result) {
252 RenderThread::Get()->AddRoute(routing_id_, this);
253 // Take a reference on behalf of the RenderThread. This will be balanced
254 // when we receive ViewMsg_Close.
255 AddRef();
256 return true;
257 } else {
258 // The above Send can fail when the tab is closing.
259 return false;
263 // This is used to complete pending inits and non-pending inits.
264 void RenderWidget::CompleteInit() {
265 DCHECK(routing_id_ != MSG_ROUTING_NONE);
267 init_complete_ = true;
269 if (webwidget_ && is_threaded_compositing_enabled_) {
270 webwidget_->enterForceCompositingMode(true);
272 if (compositor_) {
273 compositor_->setSurfaceReady();
275 DoDeferredUpdate();
277 Send(new ViewHostMsg_RenderViewReady(routing_id_));
280 void RenderWidget::SetSwappedOut(bool is_swapped_out) {
281 // We should only toggle between states.
282 DCHECK(is_swapped_out_ != is_swapped_out);
283 is_swapped_out_ = is_swapped_out;
285 // If we are swapping out, we will call ReleaseProcess, allowing the process
286 // to exit if all of its RenderViews are swapped out. We wait until the
287 // WasSwappedOut call to do this, to avoid showing the sad tab.
288 // If we are swapping in, we call AddRefProcess to prevent the process from
289 // exiting.
290 if (!is_swapped_out)
291 RenderProcess::current()->AddRefProcess();
294 bool RenderWidget::AllowPartialSwap() const {
295 return true;
298 bool RenderWidget::OnMessageReceived(const IPC::Message& message) {
299 bool handled = true;
300 IPC_BEGIN_MESSAGE_MAP(RenderWidget, message)
301 IPC_MESSAGE_HANDLER(InputMsg_HandleInputEvent, OnHandleInputEvent)
302 IPC_MESSAGE_HANDLER(InputMsg_MouseCaptureLost, OnMouseCaptureLost)
303 IPC_MESSAGE_HANDLER(InputMsg_SetFocus, OnSetFocus)
304 IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
305 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
306 IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize)
307 IPC_MESSAGE_HANDLER(ViewMsg_ChangeResizeRect, OnChangeResizeRect)
308 IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden)
309 IPC_MESSAGE_HANDLER(ViewMsg_WasShown, OnWasShown)
310 IPC_MESSAGE_HANDLER(ViewMsg_WasSwappedOut, OnWasSwappedOut)
311 IPC_MESSAGE_HANDLER(ViewMsg_UpdateRect_ACK, OnUpdateRectAck)
312 IPC_MESSAGE_HANDLER(ViewMsg_SwapBuffers_ACK,
313 OnViewContextSwapBuffersComplete)
314 IPC_MESSAGE_HANDLER(ViewMsg_SetInputMethodActive, OnSetInputMethodActive)
315 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition)
316 IPC_MESSAGE_HANDLER(ViewMsg_ImeConfirmComposition, OnImeConfirmComposition)
317 IPC_MESSAGE_HANDLER(ViewMsg_PaintAtSize, OnPaintAtSize)
318 IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnRepaint)
319 IPC_MESSAGE_HANDLER(ViewMsg_SmoothScrollCompleted, OnSmoothScrollCompleted)
320 IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection)
321 IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck)
322 IPC_MESSAGE_HANDLER(ViewMsg_ScreenInfoChanged, OnScreenInfoChanged)
323 IPC_MESSAGE_HANDLER(ViewMsg_UpdateScreenRects, OnUpdateScreenRects)
324 #if defined(OS_ANDROID)
325 IPC_MESSAGE_HANDLER(ViewMsg_ImeBatchStateChanged, OnImeBatchStateChanged)
326 IPC_MESSAGE_HANDLER(ViewMsg_ShowImeIfNeeded, OnShowImeIfNeeded)
327 #endif
328 IPC_MESSAGE_HANDLER(ViewMsg_Snapshot, OnSnapshot)
329 IPC_MESSAGE_UNHANDLED(handled = false)
330 IPC_END_MESSAGE_MAP()
331 return handled;
334 bool RenderWidget::Send(IPC::Message* message) {
335 // Don't send any messages after the browser has told us to close, and filter
336 // most outgoing messages while swapped out.
337 if ((is_swapped_out_ &&
338 !SwappedOutMessages::CanSendWhileSwappedOut(message)) ||
339 closing_) {
340 delete message;
341 return false;
344 // If given a messsage without a routing ID, then assign our routing ID.
345 if (message->routing_id() == MSG_ROUTING_NONE)
346 message->set_routing_id(routing_id_);
348 return RenderThread::Get()->Send(message);
351 void RenderWidget::Resize(const gfx::Size& new_size,
352 const gfx::Size& physical_backing_size,
353 float overdraw_bottom_height,
354 const gfx::Rect& resizer_rect,
355 bool is_fullscreen,
356 ResizeAck resize_ack) {
357 // A resize ack shouldn't be requested if we have not ACK'd the previous one.
358 DCHECK(resize_ack != SEND_RESIZE_ACK || !next_paint_is_resize_ack());
359 DCHECK(resize_ack == SEND_RESIZE_ACK || resize_ack == NO_RESIZE_ACK);
361 // Ignore this during shutdown.
362 if (!webwidget_)
363 return;
365 if (compositor_) {
366 compositor_->setViewportSize(new_size, physical_backing_size);
367 compositor_->SetOverdrawBottomHeight(overdraw_bottom_height);
370 physical_backing_size_ = physical_backing_size;
371 overdraw_bottom_height_ = overdraw_bottom_height;
372 resizer_rect_ = resizer_rect;
374 // NOTE: We may have entered fullscreen mode without changing our size.
375 bool fullscreen_change = is_fullscreen_ != is_fullscreen;
376 if (fullscreen_change)
377 WillToggleFullscreen();
378 is_fullscreen_ = is_fullscreen;
380 if (size_ != new_size) {
381 // TODO(darin): We should not need to reset this here.
382 needs_repainting_on_restore_ = false;
384 size_ = new_size;
386 paint_aggregator_.ClearPendingUpdate();
388 // When resizing, we want to wait to paint before ACK'ing the resize. This
389 // ensures that we only resize as fast as we can paint. We only need to
390 // send an ACK if we are resized to a non-empty rect.
391 webwidget_->resize(new_size);
392 if (!new_size.IsEmpty()) {
393 if (!is_accelerated_compositing_active_) {
394 // Resize should have caused an invalidation of the entire view.
395 DCHECK(paint_aggregator_.HasPendingUpdate());
398 // Send the Resize_ACK flag once we paint again if requested.
399 if (resize_ack == SEND_RESIZE_ACK)
400 set_next_paint_is_resize_ack();
402 } else {
403 resize_ack = NO_RESIZE_ACK;
406 if (fullscreen_change)
407 DidToggleFullscreen();
409 // If a resize ack is requested and it isn't set-up, then no more resizes will
410 // come in and in general things will go wrong.
411 DCHECK(resize_ack != SEND_RESIZE_ACK || new_size.IsEmpty() ||
412 next_paint_is_resize_ack());
415 void RenderWidget::OnClose() {
416 if (closing_)
417 return;
418 closing_ = true;
420 // Browser correspondence is no longer needed at this point.
421 if (routing_id_ != MSG_ROUTING_NONE) {
422 RenderThread::Get()->RemoveRoute(routing_id_);
423 SetHidden(false);
426 // If there is a Send call on the stack, then it could be dangerous to close
427 // now. Post a task that only gets invoked when there are no nested message
428 // loops.
429 MessageLoop::current()->PostNonNestableTask(
430 FROM_HERE, base::Bind(&RenderWidget::Close, this));
432 // Balances the AddRef taken when we called AddRoute.
433 Release();
436 // Got a response from the browser after the renderer decided to create a new
437 // view.
438 void RenderWidget::OnCreatingNewAck() {
439 DCHECK(routing_id_ != MSG_ROUTING_NONE);
441 CompleteInit();
444 void RenderWidget::OnResize(const gfx::Size& new_size,
445 const gfx::Size& physical_backing_size,
446 float overdraw_bottom_height,
447 const gfx::Rect& resizer_rect,
448 bool is_fullscreen) {
449 Resize(new_size, physical_backing_size, overdraw_bottom_height, resizer_rect,
450 is_fullscreen, SEND_RESIZE_ACK);
453 void RenderWidget::OnChangeResizeRect(const gfx::Rect& resizer_rect) {
454 if (resizer_rect_ != resizer_rect) {
455 gfx::Rect view_rect(size_);
457 gfx::Rect old_damage_rect = gfx::IntersectRects(view_rect, resizer_rect_);
458 if (!old_damage_rect.IsEmpty())
459 paint_aggregator_.InvalidateRect(old_damage_rect);
461 gfx::Rect new_damage_rect = gfx::IntersectRects(view_rect, resizer_rect);
462 if (!new_damage_rect.IsEmpty())
463 paint_aggregator_.InvalidateRect(new_damage_rect);
465 resizer_rect_ = resizer_rect;
467 if (webwidget_)
468 webwidget_->didChangeWindowResizerRect();
472 void RenderWidget::OnWasHidden() {
473 TRACE_EVENT0("renderer", "RenderWidget::OnWasHidden");
474 // Go into a mode where we stop generating paint and scrolling events.
475 SetHidden(true);
478 void RenderWidget::OnWasShown(bool needs_repainting) {
479 TRACE_EVENT0("renderer", "RenderWidget::OnWasShown");
480 // During shutdown we can just ignore this message.
481 if (!webwidget_)
482 return;
484 // See OnWasHidden
485 SetHidden(false);
487 if (!needs_repainting && !needs_repainting_on_restore_)
488 return;
489 needs_repainting_on_restore_ = false;
491 // Tag the next paint as a restore ack, which is picked up by
492 // DoDeferredUpdate when it sends out the next PaintRect message.
493 set_next_paint_is_restore_ack();
495 // Generate a full repaint.
496 if (!is_accelerated_compositing_active_) {
497 didInvalidateRect(gfx::Rect(size_.width(), size_.height()));
498 } else {
499 scheduleComposite();
503 void RenderWidget::OnWasSwappedOut() {
504 // If we have been swapped out and no one else is using this process,
505 // it's safe to exit now. If we get swapped back in, we will call
506 // AddRefProcess in SetSwappedOut.
507 if (is_swapped_out_)
508 RenderProcess::current()->ReleaseProcess();
511 void RenderWidget::OnRequestMoveAck() {
512 DCHECK(pending_window_rect_count_);
513 pending_window_rect_count_--;
516 void RenderWidget::OnUpdateRectAck() {
517 TRACE_EVENT0("renderer", "RenderWidget::OnUpdateRectAck");
518 DCHECK(update_reply_pending_);
519 update_reply_pending_ = false;
521 // If we sent an UpdateRect message with a zero-sized bitmap, then we should
522 // have no current paint buffer.
523 if (current_paint_buf_) {
524 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
525 current_paint_buf_ = NULL;
528 // If swapbuffers is still pending, then defer the update until the
529 // swapbuffers occurs.
530 if (num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) {
531 TRACE_EVENT0("renderer", "EarlyOut_SwapStillPending");
532 return;
535 // Notify subclasses that software rendering was flushed to the screen.
536 if (!is_accelerated_compositing_active_) {
537 DidFlushPaint();
540 // Continue painting if necessary...
541 DoDeferredUpdateAndSendInputAck();
544 bool RenderWidget::SupportsAsynchronousSwapBuffers() {
545 // Contexts using the command buffer support asynchronous swapbuffers.
546 // See RenderWidget::CreateOutputSurface().
547 if (RenderThreadImpl::current()->compositor_message_loop_proxy())
548 return false;
550 return true;
553 GURL RenderWidget::GetURLForGraphicsContext3D() {
554 return GURL();
557 bool RenderWidget::ForceCompositingModeEnabled() {
558 return false;
561 scoped_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface() {
562 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
563 if (command_line.HasSwitch(switches::kEnableSoftwareCompositingGLAdapter)) {
564 return scoped_ptr<cc::OutputSurface>(
565 new CompositorOutputSurface(routing_id(), NULL,
566 new CompositorSoftwareOutputDevice()));
569 // Explicitly disable antialiasing for the compositor. As of the time of
570 // this writing, the only platform that supported antialiasing for the
571 // compositor was Mac OS X, because the on-screen OpenGL context creation
572 // code paths on Windows and Linux didn't yet have multisampling support.
573 // Mac OS X essentially always behaves as though it's rendering offscreen.
574 // Multisampling has a heavy cost especially on devices with relatively low
575 // fill rate like most notebooks, and the Mac implementation would need to
576 // be optimized to resolve directly into the IOSurface shared between the
577 // GPU and browser processes. For these reasons and to avoid platform
578 // disparities we explicitly disable antialiasing.
579 WebKit::WebGraphicsContext3D::Attributes attributes;
580 attributes.antialias = false;
581 attributes.shareResources = true;
582 attributes.noAutomaticFlushes = true;
583 WebGraphicsContext3DCommandBufferImpl* context =
584 CreateGraphicsContext3D(attributes);
585 if (!context)
586 return scoped_ptr<cc::OutputSurface>();
588 #if defined(OS_ANDROID)
589 if (command_line.HasSwitch(switches::kEnableSynchronousRendererCompositor)) {
590 // TODO(joth): Move above the |context| creation step above when the
591 // SynchronousCompositor no longer depends on externally created context.
592 return scoped_ptr<cc::OutputSurface>(
593 new SynchronousCompositorOutputSurface(routing_id(),
594 context));
596 #endif
598 bool composite_to_mailbox =
599 command_line.HasSwitch(cc::switches::kCompositeToMailbox);
600 DCHECK(!composite_to_mailbox || command_line.HasSwitch(
601 cc::switches::kEnableCompositorFrameMessage));
602 // No swap throttling yet when compositing on the main thread.
603 DCHECK(!composite_to_mailbox || is_threaded_compositing_enabled_);
604 return scoped_ptr<cc::OutputSurface>(composite_to_mailbox ?
605 new MailboxOutputSurface(routing_id(), context, NULL) :
606 new CompositorOutputSurface(routing_id(), context, NULL));
609 void RenderWidget::OnViewContextSwapBuffersAborted() {
610 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersAborted");
611 while (!updates_pending_swap_.empty()) {
612 ViewHostMsg_UpdateRect* msg = updates_pending_swap_.front();
613 updates_pending_swap_.pop_front();
614 // msg can be NULL if the swap doesn't correspond to an DoDeferredUpdate
615 // compositing pass, hence doesn't require an UpdateRect message.
616 if (msg)
617 Send(msg);
619 num_swapbuffers_complete_pending_ = 0;
620 using_asynchronous_swapbuffers_ = false;
621 // Schedule another frame so the compositor learns about it.
622 scheduleComposite();
625 void RenderWidget::OnViewContextSwapBuffersPosted() {
626 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersPosted");
628 if (using_asynchronous_swapbuffers_) {
629 ViewHostMsg_UpdateRect* msg = NULL;
630 // pending_update_params_ can be NULL if the swap doesn't correspond to an
631 // DoDeferredUpdate compositing pass, hence doesn't require an UpdateRect
632 // message.
633 if (pending_update_params_) {
634 msg = new ViewHostMsg_UpdateRect(routing_id_, *pending_update_params_);
635 pending_update_params_.reset();
637 updates_pending_swap_.push_back(msg);
638 num_swapbuffers_complete_pending_++;
642 void RenderWidget::OnViewContextSwapBuffersComplete() {
643 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersComplete");
645 // Notify subclasses that composited rendering was flushed to the screen.
646 DidFlushPaint();
648 // When compositing deactivates, we reset the swapbuffers pending count. The
649 // swapbuffers acks may still arrive, however.
650 if (num_swapbuffers_complete_pending_ == 0) {
651 TRACE_EVENT0("renderer", "EarlyOut_ZeroSwapbuffersPending");
652 return;
654 DCHECK(!updates_pending_swap_.empty());
655 ViewHostMsg_UpdateRect* msg = updates_pending_swap_.front();
656 updates_pending_swap_.pop_front();
657 // msg can be NULL if the swap doesn't correspond to an DoDeferredUpdate
658 // compositing pass, hence doesn't require an UpdateRect message.
659 if (msg)
660 Send(msg);
661 num_swapbuffers_complete_pending_--;
663 // If update reply is still pending, then defer the update until that reply
664 // occurs.
665 if (update_reply_pending_) {
666 TRACE_EVENT0("renderer", "EarlyOut_UpdateReplyPending");
667 return;
670 // If we are not accelerated rendering, then this is a stale swapbuffers from
671 // when we were previously rendering. However, if an invalidation task is not
672 // posted, there may be software rendering work pending. In that case, don't
673 // early out.
674 if (!is_accelerated_compositing_active_ && invalidation_task_posted_) {
675 TRACE_EVENT0("renderer", "EarlyOut_AcceleratedCompositingOff");
676 return;
679 // Do not call DoDeferredUpdate unless there's animation work to be done or
680 // a real invalidation. This prevents rendering in response to a swapbuffers
681 // callback coming back after we've navigated away from the page that
682 // generated it.
683 if (!animation_update_pending_ && !paint_aggregator_.HasPendingUpdate()) {
684 TRACE_EVENT0("renderer", "EarlyOut_NoPendingUpdate");
685 return;
688 // Continue painting if necessary...
689 DoDeferredUpdateAndSendInputAck();
692 void RenderWidget::OnHandleInputEvent(const WebKit::WebInputEvent* input_event,
693 bool is_keyboard_shortcut) {
694 TRACE_EVENT0("renderer", "RenderWidget::OnHandleInputEvent");
696 handling_input_event_ = true;
697 if (!input_event) {
698 handling_input_event_ = false;
699 return;
702 base::TimeDelta now = base::TimeDelta::FromInternalValue(
703 base::TimeTicks::Now().ToInternalValue());
705 int64 delta = static_cast<int64>(
706 (now.InSecondsF() - input_event->timeStampSeconds) *
707 base::Time::kMicrosecondsPerSecond);
708 UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Renderer", delta, 0, 1000000, 100);
709 std::string name_for_event =
710 base::StringPrintf("Event.Latency.Renderer.%s",
711 GetEventName(input_event->type));
712 base::HistogramBase* counter_for_type =
713 base::Histogram::FactoryGet(
714 name_for_event,
716 1000000,
717 100,
718 base::HistogramBase::kUmaTargetedHistogramFlag);
719 counter_for_type->Add(delta);
721 bool prevent_default = false;
722 if (WebInputEvent::isMouseEventType(input_event->type)) {
723 const WebMouseEvent& mouse_event =
724 *static_cast<const WebMouseEvent*>(input_event);
725 TRACE_EVENT2("renderer", "HandleMouseMove",
726 "x", mouse_event.x, "y", mouse_event.y);
727 prevent_default = WillHandleMouseEvent(mouse_event);
730 if (WebInputEvent::isGestureEventType(input_event->type)) {
731 const WebGestureEvent& gesture_event =
732 *static_cast<const WebGestureEvent*>(input_event);
733 prevent_default = prevent_default || WillHandleGestureEvent(gesture_event);
736 if (input_event->type == WebInputEvent::GestureTap ||
737 input_event->type == WebInputEvent::GestureLongPress)
738 resetInputMethod();
740 bool processed = prevent_default;
741 if (input_event->type != WebInputEvent::Char || !suppress_next_char_events_) {
742 suppress_next_char_events_ = false;
743 if (!processed && webwidget_)
744 processed = webwidget_->handleInputEvent(*input_event);
747 // If this RawKeyDown event corresponds to a browser keyboard shortcut and
748 // it's not processed by webkit, then we need to suppress the upcoming Char
749 // events.
750 if (!processed && is_keyboard_shortcut)
751 suppress_next_char_events_ = true;
753 InputEventAckState ack_result = processed ?
754 INPUT_EVENT_ACK_STATE_CONSUMED : INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
755 if (!processed && input_event->type == WebInputEvent::TouchStart) {
756 const WebTouchEvent& touch_event =
757 *static_cast<const WebTouchEvent*>(input_event);
758 ack_result = HasTouchEventHandlersAt(touch_event.touches[0].position) ?
759 INPUT_EVENT_ACK_STATE_NOT_CONSUMED :
760 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
763 IPC::Message* response =
764 new InputHostMsg_HandleInputEvent_ACK(routing_id_, input_event->type,
765 ack_result);
766 bool event_type_gets_rate_limited =
767 input_event->type == WebInputEvent::MouseMove ||
768 input_event->type == WebInputEvent::MouseWheel ||
769 WebInputEvent::isTouchEventType(input_event->type);
771 bool frame_pending = paint_aggregator_.HasPendingUpdate();
772 if (is_accelerated_compositing_active_) {
773 frame_pending = compositor_ &&
774 compositor_->commitRequested();
777 bool is_input_throttled =
778 throttle_input_events_ &&
779 frame_pending;
781 if (event_type_gets_rate_limited && is_input_throttled && !is_hidden_) {
782 // We want to rate limit the input events in this case, so we'll wait for
783 // painting to finish before ACKing this message.
784 if (pending_input_event_ack_) {
785 // As two different kinds of events could cause us to postpone an ack
786 // we send it now, if we have one pending. The Browser should never
787 // send us the same kind of event we are delaying the ack for.
788 Send(pending_input_event_ack_.release());
790 pending_input_event_ack_.reset(response);
791 } else {
792 Send(response);
795 #if defined(OS_ANDROID)
796 // Allow the IME to be shown when the focus changes as a consequence
797 // of a processed touch end event.
798 if (input_event->type == WebInputEvent::TouchEnd && processed)
799 UpdateTextInputState(SHOW_IME_IF_NEEDED);
800 #endif
802 handling_input_event_ = false;
804 if (!prevent_default) {
805 if (WebInputEvent::isKeyboardEventType(input_event->type))
806 DidHandleKeyEvent();
807 if (WebInputEvent::isMouseEventType(input_event->type))
808 DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event)));
809 if (WebInputEvent::isTouchEventType(input_event->type))
810 DidHandleTouchEvent(*(static_cast<const WebTouchEvent*>(input_event)));
814 void RenderWidget::OnMouseCaptureLost() {
815 if (webwidget_)
816 webwidget_->mouseCaptureLost();
819 void RenderWidget::OnSetFocus(bool enable) {
820 has_focus_ = enable;
821 if (webwidget_)
822 webwidget_->setFocus(enable);
825 void RenderWidget::ClearFocus() {
826 // We may have got the focus from the browser before this gets processed, in
827 // which case we do not want to unfocus ourself.
828 if (!has_focus_ && webwidget_)
829 webwidget_->setFocus(false);
832 void RenderWidget::PaintRect(const gfx::Rect& rect,
833 const gfx::Point& canvas_origin,
834 skia::PlatformCanvas* canvas) {
835 TRACE_EVENT2("renderer", "PaintRect",
836 "width", rect.width(), "height", rect.height());
838 const bool kEnableGpuBenchmarking =
839 CommandLine::ForCurrentProcess()->HasSwitch(
840 switches::kEnableGpuBenchmarking);
841 canvas->save();
843 // Bring the canvas into the coordinate system of the paint rect.
844 canvas->translate(static_cast<SkScalar>(-canvas_origin.x()),
845 static_cast<SkScalar>(-canvas_origin.y()));
847 // If there is a custom background, tile it.
848 if (!background_.empty()) {
849 SkPaint paint;
850 skia::RefPtr<SkShader> shader = skia::AdoptRef(
851 SkShader::CreateBitmapShader(background_,
852 SkShader::kRepeat_TileMode,
853 SkShader::kRepeat_TileMode));
854 paint.setShader(shader.get());
856 // Use kSrc_Mode to handle background_ transparency properly.
857 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
859 // Canvas could contain multiple update rects. Clip to given rect so that
860 // we don't accidentally clear other update rects.
861 canvas->save();
862 canvas->scale(device_scale_factor_, device_scale_factor_);
863 canvas->clipRect(gfx::RectToSkRect(rect));
864 canvas->drawPaint(paint);
865 canvas->restore();
868 // First see if this rect is a plugin that can paint itself faster.
869 TransportDIB* optimized_dib = NULL;
870 gfx::Rect optimized_copy_rect, optimized_copy_location;
871 float dib_scale_factor;
872 webkit::ppapi::PluginInstance* optimized_instance =
873 GetBitmapForOptimizedPluginPaint(rect, &optimized_dib,
874 &optimized_copy_location,
875 &optimized_copy_rect,
876 &dib_scale_factor);
877 if (optimized_instance) {
878 // This plugin can be optimize-painted and we can just ask it to paint
879 // itself. We don't actually need the TransportDIB in this case.
881 // This is an optimization for PPAPI plugins that know they're on top of
882 // the page content. If this rect is inside such a plugin, we can save some
883 // time and avoid re-rendering the page content which we know will be
884 // covered by the plugin later (this time can be significant, especially
885 // for a playing movie that is invalidating a lot).
887 // In the plugin movie case, hopefully the similar call to
888 // GetBitmapForOptimizedPluginPaint in DoDeferredUpdate handles the
889 // painting, because that avoids copying the plugin image to a different
890 // paint rect. Unfortunately, if anything on the page is animating other
891 // than the movie, it break this optimization since the union of the
892 // invalid regions will be larger than the plugin.
894 // This code optimizes that case, where we can still avoid painting in
895 // WebKit and filling the background (which can be slow) and just painting
896 // the plugin. Unlike the DoDeferredUpdate case, an extra copy is still
897 // required.
898 base::TimeTicks paint_begin_ticks;
899 if (kEnableGpuBenchmarking)
900 paint_begin_ticks = base::TimeTicks::HighResNow();
902 SkAutoCanvasRestore auto_restore(canvas, true);
903 canvas->scale(device_scale_factor_, device_scale_factor_);
904 optimized_instance->Paint(webkit_glue::ToWebCanvas(canvas),
905 optimized_copy_location, rect);
906 canvas->restore();
907 if (kEnableGpuBenchmarking) {
908 base::TimeDelta paint_time =
909 base::TimeTicks::HighResNow() - paint_begin_ticks;
910 if (!is_accelerated_compositing_active_)
911 software_stats_.total_paint_time += paint_time;
913 } else {
914 // Normal painting case.
915 base::TimeTicks paint_begin_ticks;
916 if (kEnableGpuBenchmarking)
917 paint_begin_ticks = base::TimeTicks::HighResNow();
919 webwidget_->paint(webkit_glue::ToWebCanvas(canvas), rect);
921 if (kEnableGpuBenchmarking) {
922 base::TimeDelta paint_time =
923 base::TimeTicks::HighResNow() - paint_begin_ticks;
924 if (!is_accelerated_compositing_active_)
925 software_stats_.total_paint_time += paint_time;
928 // Flush to underlying bitmap. TODO(darin): is this needed?
929 skia::GetTopDevice(*canvas)->accessBitmap(false);
932 PaintDebugBorder(rect, canvas);
933 canvas->restore();
935 if (kEnableGpuBenchmarking) {
936 int64 num_pixels_processed = rect.width() * rect.height();
937 software_stats_.total_pixels_painted += num_pixels_processed;
941 void RenderWidget::PaintDebugBorder(const gfx::Rect& rect,
942 skia::PlatformCanvas* canvas) {
943 static bool kPaintBorder =
944 CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowPaintRects);
945 if (!kPaintBorder)
946 return;
948 // Cycle through these colors to help distinguish new paint rects.
949 const SkColor colors[] = {
950 SkColorSetARGB(0x3F, 0xFF, 0, 0),
951 SkColorSetARGB(0x3F, 0xFF, 0, 0xFF),
952 SkColorSetARGB(0x3F, 0, 0, 0xFF),
954 static int color_selector = 0;
956 SkPaint paint;
957 paint.setStyle(SkPaint::kStroke_Style);
958 paint.setColor(colors[color_selector++ % arraysize(colors)]);
959 paint.setStrokeWidth(1);
961 SkIRect irect;
962 irect.set(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1);
963 canvas->drawIRect(irect, paint);
966 void RenderWidget::AnimationCallback() {
967 TRACE_EVENT0("renderer", "RenderWidget::AnimationCallback");
968 if (!animation_update_pending_) {
969 TRACE_EVENT0("renderer", "EarlyOut_NoAnimationUpdatePending");
970 return;
972 if (!animation_floor_time_.is_null() && IsRenderingVSynced()) {
973 // Record when we fired (according to base::Time::Now()) relative to when
974 // we posted the task to quantify how much the base::Time/base::TimeTicks
975 // skew is affecting animations.
976 base::TimeDelta animation_callback_delay = base::Time::Now() -
977 (animation_floor_time_ - base::TimeDelta::FromMilliseconds(16));
978 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.AnimationCallbackDelayTime",
979 animation_callback_delay,
980 base::TimeDelta::FromMilliseconds(0),
981 base::TimeDelta::FromMilliseconds(30),
982 25);
984 DoDeferredUpdateAndSendInputAck();
987 void RenderWidget::AnimateIfNeeded() {
988 if (!animation_update_pending_)
989 return;
991 // Target 60FPS if vsync is on. Go as fast as we can if vsync is off.
992 base::TimeDelta animationInterval = IsRenderingVSynced() ?
993 base::TimeDelta::FromMilliseconds(16) : base::TimeDelta();
995 base::Time now = base::Time::Now();
997 // animation_floor_time_ is the earliest time that we should animate when
998 // using the dead reckoning software scheduler. If we're using swapbuffers
999 // complete callbacks to rate limit, we can ignore this floor.
1000 if (now >= animation_floor_time_ || num_swapbuffers_complete_pending_ > 0) {
1001 TRACE_EVENT0("renderer", "RenderWidget::AnimateIfNeeded")
1002 animation_floor_time_ = now + animationInterval;
1003 // Set a timer to call us back after animationInterval before
1004 // running animation callbacks so that if a callback requests another
1005 // we'll be sure to run it at the proper time.
1006 animation_timer_.Stop();
1007 animation_timer_.Start(FROM_HERE, animationInterval, this,
1008 &RenderWidget::AnimationCallback);
1009 animation_update_pending_ = false;
1010 if (is_accelerated_compositing_active_ && compositor_) {
1011 compositor_->Animate(base::TimeTicks::Now());
1012 } else {
1013 double frame_begin_time =
1014 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
1015 webwidget_->animate(frame_begin_time);
1017 return;
1019 TRACE_EVENT0("renderer", "EarlyOut_AnimatedTooRecently");
1020 if (!animation_timer_.IsRunning()) {
1021 // This code uses base::Time::Now() to calculate the floor and next fire
1022 // time because javascript's Date object uses base::Time::Now(). The
1023 // message loop uses base::TimeTicks, which on windows can have a
1024 // different granularity than base::Time.
1025 // The upshot of all this is that this function might be called before
1026 // base::Time::Now() has advanced past the animation_floor_time_. To
1027 // avoid exposing this delay to javascript, we keep posting delayed
1028 // tasks until base::Time::Now() has advanced far enough.
1029 base::TimeDelta delay = animation_floor_time_ - now;
1030 animation_timer_.Start(FROM_HERE, delay, this,
1031 &RenderWidget::AnimationCallback);
1035 bool RenderWidget::IsRenderingVSynced() {
1036 // TODO(nduca): Forcing a driver to disable vsync (e.g. in a control panel) is
1037 // not caught by this check. This will lead to artificially low frame rates
1038 // for people who force vsync off at a driver level and expect Chrome to speed
1039 // up.
1040 return !has_disable_gpu_vsync_switch_;
1043 void RenderWidget::InvalidationCallback() {
1044 TRACE_EVENT0("renderer", "RenderWidget::InvalidationCallback");
1045 invalidation_task_posted_ = false;
1046 DoDeferredUpdateAndSendInputAck();
1049 void RenderWidget::DoDeferredUpdateAndSendInputAck() {
1050 DoDeferredUpdate();
1052 if (pending_input_event_ack_)
1053 Send(pending_input_event_ack_.release());
1056 void RenderWidget::DoDeferredUpdate() {
1057 TRACE_EVENT0("renderer", "RenderWidget::DoDeferredUpdate");
1059 if (!webwidget_)
1060 return;
1062 if (!init_complete_) {
1063 TRACE_EVENT0("renderer", "EarlyOut_InitNotComplete");
1064 return;
1066 if (update_reply_pending_) {
1067 TRACE_EVENT0("renderer", "EarlyOut_UpdateReplyPending");
1068 return;
1070 if (is_accelerated_compositing_active_ &&
1071 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) {
1072 TRACE_EVENT0("renderer", "EarlyOut_MaxSwapBuffersPending");
1073 return;
1076 // Suppress updating when we are hidden.
1077 if (is_hidden_ || size_.IsEmpty() || is_swapped_out_) {
1078 paint_aggregator_.ClearPendingUpdate();
1079 needs_repainting_on_restore_ = true;
1080 TRACE_EVENT0("renderer", "EarlyOut_NotVisible");
1081 return;
1084 if (is_accelerated_compositing_active_)
1085 using_asynchronous_swapbuffers_ = SupportsAsynchronousSwapBuffers();
1087 // Tracking of frame rate jitter
1088 base::TimeTicks frame_begin_ticks = base::TimeTicks::Now();
1089 InstrumentWillBeginFrame();
1090 AnimateIfNeeded();
1092 // Layout may generate more invalidation. It may also enable the
1093 // GPU acceleration, so make sure to run layout before we send the
1094 // GpuRenderingActivated message.
1095 webwidget_->layout();
1097 // The following two can result in further layout and possibly
1098 // enable GPU acceleration so they need to be called before any painting
1099 // is done.
1100 UpdateTextInputState(DO_NOT_SHOW_IME);
1101 UpdateSelectionBounds();
1103 // Suppress painting if nothing is dirty. This has to be done after updating
1104 // animations running layout as these may generate further invalidations.
1105 if (!paint_aggregator_.HasPendingUpdate()) {
1106 TRACE_EVENT0("renderer", "EarlyOut_NoPendingUpdate");
1107 InstrumentDidCancelFrame();
1108 return;
1111 if (!is_accelerated_compositing_active_ &&
1112 !is_threaded_compositing_enabled_ &&
1113 ForceCompositingModeEnabled()) {
1114 webwidget_->enterForceCompositingMode(true);
1117 if (!last_do_deferred_update_time_.is_null()) {
1118 base::TimeDelta delay = frame_begin_ticks - last_do_deferred_update_time_;
1119 if (is_accelerated_compositing_active_) {
1120 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.AccelDoDeferredUpdateDelay",
1121 delay,
1122 base::TimeDelta::FromMilliseconds(1),
1123 base::TimeDelta::FromMilliseconds(120),
1124 60);
1125 } else {
1126 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.SoftwareDoDeferredUpdateDelay",
1127 delay,
1128 base::TimeDelta::FromMilliseconds(1),
1129 base::TimeDelta::FromMilliseconds(120),
1130 60);
1133 // Calculate filtered time per frame:
1134 float frame_time_elapsed = static_cast<float>(delay.InSecondsF());
1135 filtered_time_per_frame_ =
1136 0.9f * filtered_time_per_frame_ + 0.1f * frame_time_elapsed;
1138 last_do_deferred_update_time_ = frame_begin_ticks;
1140 if (!is_accelerated_compositing_active_) {
1141 software_stats_.animation_frame_count++;
1142 software_stats_.screen_frame_count++;
1145 // OK, save the pending update to a local since painting may cause more
1146 // invalidation. Some WebCore rendering objects only layout when painted.
1147 PaintAggregator::PendingUpdate update;
1148 paint_aggregator_.PopPendingUpdate(&update);
1150 gfx::Rect scroll_damage = update.GetScrollDamage();
1151 gfx::Rect bounds = gfx::UnionRects(update.GetPaintBounds(), scroll_damage);
1153 // Notify derived classes that we're about to initiate a paint.
1154 WillInitiatePaint();
1156 // A plugin may be able to do an optimized paint. First check this, in which
1157 // case we can skip all of the bitmap generation and regular paint code.
1158 // This optimization allows PPAPI plugins that declare themselves on top of
1159 // the page (like a traditional windowed plugin) to be able to animate (think
1160 // movie playing) without repeatedly re-painting the page underneath, or
1161 // copying the plugin backing store (since we can send the plugin's backing
1162 // store directly to the browser).
1164 // This optimization only works when the entire invalid region is contained
1165 // within the plugin. There is a related optimization in PaintRect for the
1166 // case where there may be multiple invalid regions.
1167 TransportDIB* dib = NULL;
1168 gfx::Rect optimized_copy_rect, optimized_copy_location;
1169 float dib_scale_factor = 1;
1170 DCHECK(!pending_update_params_.get());
1171 pending_update_params_.reset(new ViewHostMsg_UpdateRect_Params);
1172 pending_update_params_->scroll_delta = update.scroll_delta;
1173 pending_update_params_->scroll_rect = update.scroll_rect;
1174 pending_update_params_->view_size = size_;
1175 pending_update_params_->plugin_window_moves.swap(plugin_window_moves_);
1176 pending_update_params_->flags = next_paint_flags_;
1177 pending_update_params_->scroll_offset = GetScrollOffset();
1178 pending_update_params_->needs_ack = true;
1179 pending_update_params_->scale_factor = device_scale_factor_;
1180 next_paint_flags_ = 0;
1181 need_update_rect_for_auto_resize_ = false;
1183 if (update.scroll_rect.IsEmpty() &&
1184 !is_accelerated_compositing_active_ &&
1185 GetBitmapForOptimizedPluginPaint(bounds, &dib, &optimized_copy_location,
1186 &optimized_copy_rect,
1187 &dib_scale_factor)) {
1188 // Only update the part of the plugin that actually changed.
1189 optimized_copy_rect.Intersect(bounds);
1190 pending_update_params_->bitmap = dib->id();
1191 pending_update_params_->bitmap_rect = optimized_copy_location;
1192 pending_update_params_->copy_rects.push_back(optimized_copy_rect);
1193 pending_update_params_->scale_factor = dib_scale_factor;
1194 } else if (!is_accelerated_compositing_active_) {
1195 // Compute a buffer for painting and cache it.
1197 bool fractional_scale = device_scale_factor_ -
1198 static_cast<int>(device_scale_factor_) != 0;
1199 if (fractional_scale) {
1200 // Damage might not be DIP aligned. Inflate damage to compensate.
1201 bounds.Inset(-1, -1);
1202 bounds.Intersect(gfx::Rect(size_));
1205 gfx::Rect pixel_bounds = gfx::ToEnclosingRect(
1206 gfx::ScaleRect(bounds, device_scale_factor_));
1208 scoped_ptr<skia::PlatformCanvas> canvas(
1209 RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_,
1210 pixel_bounds));
1211 if (!canvas) {
1212 NOTREACHED();
1213 return;
1216 // We may get back a smaller canvas than we asked for.
1217 // TODO(darin): This seems like it could cause painting problems!
1218 DCHECK_EQ(pixel_bounds.width(), canvas->getDevice()->width());
1219 DCHECK_EQ(pixel_bounds.height(), canvas->getDevice()->height());
1220 pixel_bounds.set_width(canvas->getDevice()->width());
1221 pixel_bounds.set_height(canvas->getDevice()->height());
1222 bounds.set_width(pixel_bounds.width() / device_scale_factor_);
1223 bounds.set_height(pixel_bounds.height() / device_scale_factor_);
1225 HISTOGRAM_COUNTS_100("MPArch.RW_PaintRectCount", update.paint_rects.size());
1227 pending_update_params_->bitmap = current_paint_buf_->id();
1228 pending_update_params_->bitmap_rect = bounds;
1230 std::vector<gfx::Rect>& copy_rects = pending_update_params_->copy_rects;
1231 // The scroll damage is just another rectangle to paint and copy.
1232 copy_rects.swap(update.paint_rects);
1233 if (!scroll_damage.IsEmpty())
1234 copy_rects.push_back(scroll_damage);
1236 for (size_t i = 0; i < copy_rects.size(); ++i) {
1237 gfx::Rect rect = copy_rects[i];
1238 if (fractional_scale) {
1239 // Damage might not be DPI aligned. Inflate rect to compensate.
1240 rect.Inset(-1, -1);
1242 PaintRect(rect, pixel_bounds.origin(), canvas.get());
1245 // Software FPS tick for performance tests. The accelerated path traces the
1246 // frame events in didCommitAndDrawCompositorFrame. See throughput_tests.cc.
1247 // NOTE: Tests may break if this event is renamed or moved.
1248 UNSHIPPED_TRACE_EVENT_INSTANT0("test_fps", "TestFrameTickSW",
1249 TRACE_EVENT_SCOPE_THREAD);
1250 } else { // Accelerated compositing path
1251 // Begin painting.
1252 // If painting is done via the gpu process then we don't set any damage
1253 // rects to save the browser process from doing unecessary work.
1254 pending_update_params_->bitmap_rect = bounds;
1255 pending_update_params_->scroll_rect = gfx::Rect();
1256 // We don't need an ack, because we're not sharing a DIB with the browser.
1257 // If it needs to (e.g. composited UI), the GPU process does its own ACK
1258 // with the browser for the GPU surface.
1259 pending_update_params_->needs_ack = false;
1260 Composite(frame_begin_ticks);
1263 // If we're holding a pending input event ACK, send the ACK before sending the
1264 // UpdateReply message so we can receive another input event before the
1265 // UpdateRect_ACK on platforms where the UpdateRect_ACK is sent from within
1266 // the UpdateRect IPC message handler.
1267 if (pending_input_event_ack_)
1268 Send(pending_input_event_ack_.release());
1270 // If Composite() called SwapBuffers, pending_update_params_ will be reset (in
1271 // OnSwapBuffersPosted), meaning a message has been added to the
1272 // updates_pending_swap_ queue, that will be sent later. Otherwise, we send
1273 // the message now.
1274 if (pending_update_params_) {
1275 // sending an ack to browser process that the paint is complete...
1276 update_reply_pending_ = pending_update_params_->needs_ack;
1277 Send(new ViewHostMsg_UpdateRect(routing_id_, *pending_update_params_));
1278 pending_update_params_.reset();
1281 // If we're software rendering then we're done initiating the paint.
1282 if (!is_accelerated_compositing_active_)
1283 DidInitiatePaint();
1286 void RenderWidget::Composite(base::TimeTicks frame_begin_time) {
1287 DCHECK(is_accelerated_compositing_active_);
1288 if (compositor_) // TODO(jamesr): Figure out how this can be null.
1289 compositor_->Composite(frame_begin_time);
1292 ///////////////////////////////////////////////////////////////////////////////
1293 // WebWidgetClient
1295 void RenderWidget::didInvalidateRect(const WebRect& rect) {
1296 TRACE_EVENT2("renderer", "RenderWidget::didInvalidateRect",
1297 "width", rect.width, "height", rect.height);
1298 // The invalidated rect might be outside the bounds of the view.
1299 gfx::Rect view_rect(size_);
1300 gfx::Rect damaged_rect = gfx::IntersectRects(view_rect, rect);
1301 if (damaged_rect.IsEmpty())
1302 return;
1304 paint_aggregator_.InvalidateRect(damaged_rect);
1306 // We may not need to schedule another call to DoDeferredUpdate.
1307 if (invalidation_task_posted_)
1308 return;
1309 if (!paint_aggregator_.HasPendingUpdate())
1310 return;
1311 if (update_reply_pending_ ||
1312 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending)
1313 return;
1315 // When GPU rendering, combine pending animations and invalidations into
1316 // a single update.
1317 if (is_accelerated_compositing_active_ &&
1318 animation_update_pending_ &&
1319 animation_timer_.IsRunning())
1320 return;
1322 // Perform updating asynchronously. This serves two purposes:
1323 // 1) Ensures that we call WebView::Paint without a bunch of other junk
1324 // on the call stack.
1325 // 2) Allows us to collect more damage rects before painting to help coalesce
1326 // the work that we will need to do.
1327 invalidation_task_posted_ = true;
1328 MessageLoop::current()->PostTask(
1329 FROM_HERE, base::Bind(&RenderWidget::InvalidationCallback, this));
1332 void RenderWidget::didScrollRect(int dx, int dy,
1333 const WebRect& clip_rect) {
1334 // Drop scrolls on the floor when we are in compositing mode.
1335 // TODO(nduca): stop WebViewImpl from sending scrolls in the first place.
1336 if (is_accelerated_compositing_active_)
1337 return;
1339 // The scrolled rect might be outside the bounds of the view.
1340 gfx::Rect view_rect(size_);
1341 gfx::Rect damaged_rect = gfx::IntersectRects(view_rect, clip_rect);
1342 if (damaged_rect.IsEmpty())
1343 return;
1345 paint_aggregator_.ScrollRect(gfx::Vector2d(dx, dy), damaged_rect);
1347 // We may not need to schedule another call to DoDeferredUpdate.
1348 if (invalidation_task_posted_)
1349 return;
1350 if (!paint_aggregator_.HasPendingUpdate())
1351 return;
1352 if (update_reply_pending_ ||
1353 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending)
1354 return;
1356 // When GPU rendering, combine pending animations and invalidations into
1357 // a single update.
1358 if (is_accelerated_compositing_active_ &&
1359 animation_update_pending_ &&
1360 animation_timer_.IsRunning())
1361 return;
1363 // Perform updating asynchronously. This serves two purposes:
1364 // 1) Ensures that we call WebView::Paint without a bunch of other junk
1365 // on the call stack.
1366 // 2) Allows us to collect more damage rects before painting to help coalesce
1367 // the work that we will need to do.
1368 invalidation_task_posted_ = true;
1369 MessageLoop::current()->PostTask(
1370 FROM_HERE, base::Bind(&RenderWidget::InvalidationCallback, this));
1373 void RenderWidget::didAutoResize(const WebSize& new_size) {
1374 if (size_.width() != new_size.width || size_.height() != new_size.height) {
1375 size_ = new_size;
1376 // If we don't clear PaintAggregator after changing autoResize state, then
1377 // we might end up in a situation where bitmap_rect is larger than the
1378 // view_size. By clearing PaintAggregator, we ensure that we don't end up
1379 // with invalid damage rects.
1380 paint_aggregator_.ClearPendingUpdate();
1382 if (auto_resize_mode_)
1383 AutoResizeCompositor();
1385 if (RenderThreadImpl::current()->short_circuit_size_updates()) {
1386 setWindowRect(WebRect(rootWindowRect().x,
1387 rootWindowRect().y,
1388 new_size.width,
1389 new_size.height));
1390 } else {
1391 need_update_rect_for_auto_resize_ = true;
1396 void RenderWidget::AutoResizeCompositor() {
1397 physical_backing_size_ = gfx::ToCeiledSize(gfx::ScaleSize(size_,
1398 device_scale_factor_));
1399 if (compositor_)
1400 compositor_->setViewportSize(size_, physical_backing_size_);
1403 void RenderWidget::didActivateCompositor(int input_handler_identifier) {
1404 TRACE_EVENT0("gpu", "RenderWidget::didActivateCompositor");
1406 #if !defined(OS_MACOSX)
1407 if (!is_accelerated_compositing_active_) {
1408 // When not in accelerated compositing mode, in certain cases (e.g. waiting
1409 // for a resize or if no backing store) the RenderWidgetHost is blocking the
1410 // browser's UI thread for some time, waiting for an UpdateRect. If we are
1411 // going to switch to accelerated compositing, the GPU process may need
1412 // round-trips to the browser's UI thread before finishing the frame,
1413 // causing deadlocks if we delay the UpdateRect until we receive the
1414 // OnSwapBuffersComplete. So send a dummy message that will unblock the
1415 // browser's UI thread. This is not necessary on Mac, because SwapBuffers
1416 // now unblocks GetBackingStore on Mac.
1417 Send(new ViewHostMsg_UpdateIsDelayed(routing_id_));
1419 #endif
1421 is_accelerated_compositing_active_ = true;
1422 Send(new ViewHostMsg_DidActivateAcceleratedCompositing(
1423 routing_id_, is_accelerated_compositing_active_));
1426 void RenderWidget::didDeactivateCompositor() {
1427 TRACE_EVENT0("gpu", "RenderWidget::didDeactivateCompositor");
1429 is_accelerated_compositing_active_ = false;
1430 Send(new ViewHostMsg_DidActivateAcceleratedCompositing(
1431 routing_id_, is_accelerated_compositing_active_));
1433 if (using_asynchronous_swapbuffers_)
1434 using_asynchronous_swapbuffers_ = false;
1436 // In single-threaded mode, we exit force compositing mode and re-enter in
1437 // DoDeferredUpdate() if appropriate. In threaded compositing mode,
1438 // DoDeferredUpdate() is bypassed and WebKit is responsible for exiting and
1439 // entering force compositing mode at the appropriate times.
1440 if (!is_threaded_compositing_enabled_)
1441 webwidget_->enterForceCompositingMode(false);
1444 void RenderWidget::initializeLayerTreeView() {
1445 compositor_ = RenderWidgetCompositor::Create(this);
1446 if (!compositor_)
1447 return;
1449 compositor_->setViewportSize(size_, physical_backing_size_);
1450 if (init_complete_)
1451 compositor_->setSurfaceReady();
1454 WebKit::WebLayerTreeView* RenderWidget::layerTreeView() {
1455 return compositor_.get();
1458 void RenderWidget::suppressCompositorScheduling(bool enable) {
1459 if (compositor_)
1460 compositor_->SetSuppressScheduleComposite(enable);
1463 void RenderWidget::willBeginCompositorFrame() {
1464 TRACE_EVENT0("gpu", "RenderWidget::willBeginCompositorFrame");
1466 DCHECK(RenderThreadImpl::current()->compositor_message_loop_proxy());
1468 // The following two can result in further layout and possibly
1469 // enable GPU acceleration so they need to be called before any painting
1470 // is done.
1471 UpdateTextInputState(DO_NOT_SHOW_IME);
1472 UpdateSelectionBounds();
1474 WillInitiatePaint();
1477 void RenderWidget::didBecomeReadyForAdditionalInput() {
1478 TRACE_EVENT0("renderer", "RenderWidget::didBecomeReadyForAdditionalInput");
1479 if (pending_input_event_ack_)
1480 Send(pending_input_event_ack_.release());
1483 void RenderWidget::DidCommitCompositorFrame() {
1486 void RenderWidget::didCommitAndDrawCompositorFrame() {
1487 TRACE_EVENT0("gpu", "RenderWidget::didCommitAndDrawCompositorFrame");
1488 // Accelerated FPS tick for performance tests. See throughput_tests.cc.
1489 // NOTE: Tests may break if this event is renamed or moved.
1490 UNSHIPPED_TRACE_EVENT_INSTANT0("test_fps", "TestFrameTickGPU",
1491 TRACE_EVENT_SCOPE_THREAD);
1492 // Notify subclasses that we initiated the paint operation.
1493 DidInitiatePaint();
1496 void RenderWidget::didCompleteSwapBuffers() {
1497 TRACE_EVENT0("renderer", "RenderWidget::didCompleteSwapBuffers");
1499 // Notify subclasses threaded composited rendering was flushed to the screen.
1500 DidFlushPaint();
1502 if (update_reply_pending_)
1503 return;
1505 if (!next_paint_flags_ &&
1506 !need_update_rect_for_auto_resize_ &&
1507 !plugin_window_moves_.size()) {
1508 return;
1511 ViewHostMsg_UpdateRect_Params params;
1512 params.view_size = size_;
1513 params.plugin_window_moves.swap(plugin_window_moves_);
1514 params.flags = next_paint_flags_;
1515 params.scroll_offset = GetScrollOffset();
1516 params.needs_ack = false;
1517 params.scale_factor = device_scale_factor_;
1519 Send(new ViewHostMsg_UpdateRect(routing_id_, params));
1520 next_paint_flags_ = 0;
1521 need_update_rect_for_auto_resize_ = false;
1524 void RenderWidget::scheduleComposite() {
1525 TRACE_EVENT0("gpu", "RenderWidget::scheduleComposite");
1526 if (RenderThreadImpl::current()->compositor_message_loop_proxy() &&
1527 compositor_) {
1528 compositor_->setNeedsRedraw();
1529 } else {
1530 // TODO(nduca): replace with something a little less hacky. The reason this
1531 // hack is still used is because the Invalidate-DoDeferredUpdate loop
1532 // contains a lot of host-renderer synchronization logic that is still
1533 // important for the accelerated compositing case. The option of simply
1534 // duplicating all that code is less desirable than "faking out" the
1535 // invalidation path using a magical damage rect.
1536 didInvalidateRect(WebRect(0, 0, 1, 1));
1540 void RenderWidget::scheduleAnimation() {
1541 if (animation_update_pending_)
1542 return;
1544 TRACE_EVENT0("gpu", "RenderWidget::scheduleAnimation");
1545 animation_update_pending_ = true;
1546 if (!animation_timer_.IsRunning()) {
1547 animation_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(0), this,
1548 &RenderWidget::AnimationCallback);
1552 void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) {
1553 // TODO(darin): Eliminate this temporary.
1554 WebCursor cursor(cursor_info);
1556 // Only send a SetCursor message if we need to make a change.
1557 if (!current_cursor_.IsEqual(cursor)) {
1558 current_cursor_ = cursor;
1559 Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
1563 // We are supposed to get a single call to Show for a newly created RenderWidget
1564 // that was created via RenderWidget::CreateWebView. So, we wait until this
1565 // point to dispatch the ShowWidget message.
1567 // This method provides us with the information about how to display the newly
1568 // created RenderWidget (i.e., as a blocked popup or as a new tab).
1570 void RenderWidget::show(WebNavigationPolicy) {
1571 DCHECK(!did_show_) << "received extraneous Show call";
1572 DCHECK(routing_id_ != MSG_ROUTING_NONE);
1573 DCHECK(opener_id_ != MSG_ROUTING_NONE);
1575 if (did_show_)
1576 return;
1578 did_show_ = true;
1579 // NOTE: initial_pos_ may still have its default values at this point, but
1580 // that's okay. It'll be ignored if as_popup is false, or the browser
1581 // process will impose a default position otherwise.
1582 Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_pos_));
1583 SetPendingWindowRect(initial_pos_);
1586 void RenderWidget::didFocus() {
1589 void RenderWidget::didBlur() {
1592 void RenderWidget::DoDeferredClose() {
1593 Send(new ViewHostMsg_Close(routing_id_));
1596 void RenderWidget::closeWidgetSoon() {
1597 if (is_swapped_out_) {
1598 // This widget is currently swapped out, and the active widget is in a
1599 // different process. Have the browser route the close request to the
1600 // active widget instead, so that the correct unload handlers are run.
1601 Send(new ViewHostMsg_RouteCloseEvent(routing_id_));
1602 return;
1605 // If a page calls window.close() twice, we'll end up here twice, but that's
1606 // OK. It is safe to send multiple Close messages.
1608 // Ask the RenderWidgetHost to initiate close. We could be called from deep
1609 // in Javascript. If we ask the RendwerWidgetHost to close now, the window
1610 // could be closed before the JS finishes executing. So instead, post a
1611 // message back to the message loop, which won't run until the JS is
1612 // complete, and then the Close message can be sent.
1613 MessageLoop::current()->PostTask(
1614 FROM_HERE, base::Bind(&RenderWidget::DoDeferredClose, this));
1617 void RenderWidget::Close() {
1618 if (webwidget_) {
1619 webwidget_->willCloseLayerTreeView();
1620 compositor_.reset();
1621 webwidget_->close();
1622 webwidget_ = NULL;
1626 WebRect RenderWidget::windowRect() {
1627 if (pending_window_rect_count_)
1628 return pending_window_rect_;
1630 return view_screen_rect_;
1633 void RenderWidget::setToolTipText(const WebKit::WebString& text,
1634 WebTextDirection hint) {
1635 Send(new ViewHostMsg_SetTooltipText(routing_id_, text, hint));
1638 void RenderWidget::setWindowRect(const WebRect& pos) {
1639 if (did_show_) {
1640 if (!RenderThreadImpl::current()->short_circuit_size_updates()) {
1641 Send(new ViewHostMsg_RequestMove(routing_id_, pos));
1642 SetPendingWindowRect(pos);
1643 } else {
1644 WebSize new_size(pos.width, pos.height);
1645 Resize(new_size, new_size, overdraw_bottom_height_,
1646 WebRect(), is_fullscreen_, NO_RESIZE_ACK);
1647 view_screen_rect_ = pos;
1648 window_screen_rect_ = pos;
1650 } else {
1651 initial_pos_ = pos;
1655 void RenderWidget::SetPendingWindowRect(const WebRect& rect) {
1656 pending_window_rect_ = rect;
1657 pending_window_rect_count_++;
1660 WebRect RenderWidget::rootWindowRect() {
1661 if (pending_window_rect_count_) {
1662 // NOTE(mbelshe): If there is a pending_window_rect_, then getting
1663 // the RootWindowRect is probably going to return wrong results since the
1664 // browser may not have processed the Move yet. There isn't really anything
1665 // good to do in this case, and it shouldn't happen - since this size is
1666 // only really needed for windowToScreen, which is only used for Popups.
1667 return pending_window_rect_;
1670 return window_screen_rect_;
1673 WebRect RenderWidget::windowResizerRect() {
1674 return resizer_rect_;
1677 void RenderWidget::OnSetInputMethodActive(bool is_active) {
1678 // To prevent this renderer process from sending unnecessary IPC messages to
1679 // a browser process, we permit the renderer process to send IPC messages
1680 // only during the input method attached to the browser process is active.
1681 input_method_is_active_ = is_active;
1684 void RenderWidget::UpdateCompositionInfo(
1685 const ui::Range& range,
1686 const std::vector<gfx::Rect>& character_bounds) {
1687 if (!ShouldUpdateCompositionInfo(range, character_bounds))
1688 return;
1689 composition_character_bounds_ = character_bounds;
1690 composition_range_ = range;
1691 Send(new ViewHostMsg_ImeCompositionRangeChanged(
1692 routing_id(), composition_range_, composition_character_bounds_));
1695 void RenderWidget::OnImeSetComposition(
1696 const string16& text,
1697 const std::vector<WebCompositionUnderline>& underlines,
1698 int selection_start, int selection_end) {
1699 if (!webwidget_)
1700 return;
1701 DCHECK(!handling_ime_event_);
1702 handling_ime_event_ = true;
1703 if (webwidget_->setComposition(
1704 text, WebVector<WebCompositionUnderline>(underlines),
1705 selection_start, selection_end)) {
1706 // Setting the IME composition was successful. Send the new composition
1707 // range to the browser.
1708 ui::Range range(ui::Range::InvalidRange());
1709 size_t location, length;
1710 if (webwidget_->compositionRange(&location, &length)) {
1711 range.set_start(location);
1712 range.set_end(location + length);
1714 // The IME was cancelled via the Esc key, so just send back the caret.
1715 else if (webwidget_->caretOrSelectionRange(&location, &length)) {
1716 range.set_start(location);
1717 range.set_end(location + length);
1719 std::vector<gfx::Rect> character_bounds;
1720 GetCompositionCharacterBounds(&character_bounds);
1721 UpdateCompositionInfo(range, character_bounds);
1722 } else {
1723 // If we failed to set the composition text, then we need to let the browser
1724 // process to cancel the input method's ongoing composition session, to make
1725 // sure we are in a consistent state.
1726 Send(new ViewHostMsg_ImeCancelComposition(routing_id()));
1728 // Send an updated IME range with just the caret range.
1729 ui::Range range(ui::Range::InvalidRange());
1730 size_t location, length;
1731 if (webwidget_->caretOrSelectionRange(&location, &length)) {
1732 range.set_start(location);
1733 range.set_end(location + length);
1735 UpdateCompositionInfo(range, std::vector<gfx::Rect>());
1737 handling_ime_event_ = false;
1738 UpdateTextInputState(DO_NOT_SHOW_IME);
1741 void RenderWidget::OnImeConfirmComposition(
1742 const string16& text, const ui::Range& replacement_range) {
1743 if (!webwidget_)
1744 return;
1745 DCHECK(!handling_ime_event_);
1746 handling_ime_event_ = true;
1747 handling_input_event_ = true;
1748 webwidget_->confirmComposition(text);
1749 handling_input_event_ = false;
1751 // Send an updated IME range with just the caret range.
1752 ui::Range range(ui::Range::InvalidRange());
1753 size_t location, length;
1754 if (webwidget_->caretOrSelectionRange(&location, &length)) {
1755 range.set_start(location);
1756 range.set_end(location + length);
1758 UpdateCompositionInfo(range, std::vector<gfx::Rect>());
1759 handling_ime_event_ = false;
1760 UpdateTextInputState(DO_NOT_SHOW_IME);
1763 // This message causes the renderer to render an image of the
1764 // desired_size, regardless of whether the tab is hidden or not.
1765 void RenderWidget::OnPaintAtSize(const TransportDIB::Handle& dib_handle,
1766 int tag,
1767 const gfx::Size& page_size,
1768 const gfx::Size& desired_size) {
1769 if (!webwidget_ || !TransportDIB::is_valid_handle(dib_handle)) {
1770 if (TransportDIB::is_valid_handle(dib_handle)) {
1771 // Close our unused handle.
1772 #if defined(OS_WIN)
1773 ::CloseHandle(dib_handle);
1774 #elif defined(OS_MACOSX)
1775 base::SharedMemory::CloseHandle(dib_handle);
1776 #endif
1778 return;
1781 if (page_size.IsEmpty() || desired_size.IsEmpty()) {
1782 // If one of these is empty, then we just return the dib we were
1783 // given, to avoid leaking it.
1784 Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, desired_size));
1785 return;
1788 // Map the given DIB ID into this process, and unmap it at the end
1789 // of this function.
1790 scoped_ptr<TransportDIB> paint_at_size_buffer(
1791 TransportDIB::CreateWithHandle(dib_handle));
1793 gfx::Size page_size_in_pixel = gfx::ToFlooredSize(
1794 gfx::ScaleSize(page_size, device_scale_factor_));
1795 gfx::Size desired_size_in_pixel = gfx::ToFlooredSize(
1796 gfx::ScaleSize(desired_size, device_scale_factor_));
1797 gfx::Size canvas_size = page_size_in_pixel;
1798 float x_scale = static_cast<float>(desired_size_in_pixel.width()) /
1799 static_cast<float>(canvas_size.width());
1800 float y_scale = static_cast<float>(desired_size_in_pixel.height()) /
1801 static_cast<float>(canvas_size.height());
1803 gfx::Rect orig_bounds(canvas_size);
1804 canvas_size.set_width(static_cast<int>(canvas_size.width() * x_scale));
1805 canvas_size.set_height(static_cast<int>(canvas_size.height() * y_scale));
1806 gfx::Rect bounds(canvas_size);
1808 scoped_ptr<skia::PlatformCanvas> canvas(
1809 paint_at_size_buffer->GetPlatformCanvas(canvas_size.width(),
1810 canvas_size.height()));
1811 if (!canvas) {
1812 NOTREACHED();
1813 return;
1816 // Reset bounds to what we actually received, but they should be the
1817 // same.
1818 DCHECK_EQ(bounds.width(), canvas->getDevice()->width());
1819 DCHECK_EQ(bounds.height(), canvas->getDevice()->height());
1820 bounds.set_width(canvas->getDevice()->width());
1821 bounds.set_height(canvas->getDevice()->height());
1823 canvas->save();
1824 // Add the scale factor to the canvas, so that we'll get the desired size.
1825 canvas->scale(SkFloatToScalar(x_scale), SkFloatToScalar(y_scale));
1827 // Have to make sure we're laid out at the right size before
1828 // rendering.
1829 gfx::Size old_size = webwidget_->size();
1830 webwidget_->resize(page_size);
1831 webwidget_->layout();
1833 // Paint the entire thing (using original bounds, not scaled bounds).
1834 PaintRect(orig_bounds, orig_bounds.origin(), canvas.get());
1835 canvas->restore();
1837 // Return the widget to its previous size.
1838 webwidget_->resize(old_size);
1840 Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, bounds.size()));
1843 void RenderWidget::OnSnapshot(const gfx::Rect& src_subrect) {
1844 SkBitmap snapshot;
1846 if (OnSnapshotHelper(src_subrect, &snapshot)) {
1847 Send(new ViewHostMsg_Snapshot(routing_id(), true, snapshot));
1848 } else {
1849 Send(new ViewHostMsg_Snapshot(routing_id(), false, SkBitmap()));
1853 bool RenderWidget::OnSnapshotHelper(const gfx::Rect& src_subrect,
1854 SkBitmap* snapshot) {
1855 base::TimeTicks beginning_time = base::TimeTicks::Now();
1857 if (!webwidget_ || src_subrect.IsEmpty())
1858 return false;
1860 gfx::Rect viewport_size = gfx::IntersectRects(
1861 src_subrect, gfx::Rect(physical_backing_size_));
1863 skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(
1864 skia::CreatePlatformCanvas(viewport_size.width(),
1865 viewport_size.height(),
1866 true,
1867 NULL,
1868 skia::RETURN_NULL_ON_FAILURE));
1869 if (!canvas)
1870 return false;
1872 canvas->save();
1873 webwidget_->layout();
1875 PaintRect(viewport_size, viewport_size.origin(), canvas.get());
1876 canvas->restore();
1878 const SkBitmap& bitmap = skia::GetTopDevice(*canvas)->accessBitmap(false);
1879 if (!bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config))
1880 return false;
1882 UMA_HISTOGRAM_TIMES("Renderer4.Snapshot",
1883 base::TimeTicks::Now() - beginning_time);
1884 return true;
1887 void RenderWidget::OnRepaint(gfx::Size size_to_paint) {
1888 // During shutdown we can just ignore this message.
1889 if (!webwidget_)
1890 return;
1892 // Even if the browser provides an empty damage rect, it's still expecting to
1893 // receive a repaint ack so just damage the entire widget bounds.
1894 if (size_to_paint.IsEmpty()) {
1895 size_to_paint = size_;
1898 set_next_paint_is_repaint_ack();
1899 if (is_accelerated_compositing_active_ && compositor_) {
1900 compositor_->SetNeedsRedrawRect(gfx::Rect(size_to_paint));
1901 } else {
1902 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height());
1903 didInvalidateRect(repaint_rect);
1907 void RenderWidget::OnSmoothScrollCompleted() {
1908 pending_smooth_scroll_gesture_.Run();
1911 void RenderWidget::OnSetTextDirection(WebTextDirection direction) {
1912 if (!webwidget_)
1913 return;
1914 webwidget_->setTextDirection(direction);
1917 void RenderWidget::OnScreenInfoChanged(
1918 const WebKit::WebScreenInfo& screen_info) {
1919 screen_info_ = screen_info;
1920 SetDeviceScaleFactor(screen_info.deviceScaleFactor);
1923 void RenderWidget::OnUpdateScreenRects(const gfx::Rect& view_screen_rect,
1924 const gfx::Rect& window_screen_rect) {
1925 view_screen_rect_ = view_screen_rect;
1926 window_screen_rect_ = window_screen_rect;
1927 Send(new ViewHostMsg_UpdateScreenRects_ACK(routing_id()));
1930 #if defined(OS_ANDROID)
1931 void RenderWidget::OnImeBatchStateChanged(bool is_begin) {
1932 Send(new ViewHostMsg_ImeBatchStateChanged_ACK(routing_id(), is_begin));
1935 void RenderWidget::OnShowImeIfNeeded() {
1936 UpdateTextInputState(SHOW_IME_IF_NEEDED);
1938 #endif
1940 void RenderWidget::SetDeviceScaleFactor(float device_scale_factor) {
1941 if (device_scale_factor_ == device_scale_factor)
1942 return;
1944 device_scale_factor_ = device_scale_factor;
1946 if (!is_accelerated_compositing_active_) {
1947 didInvalidateRect(gfx::Rect(size_.width(), size_.height()));
1948 } else {
1949 scheduleComposite();
1953 webkit::ppapi::PluginInstance* RenderWidget::GetBitmapForOptimizedPluginPaint(
1954 const gfx::Rect& paint_bounds,
1955 TransportDIB** dib,
1956 gfx::Rect* location,
1957 gfx::Rect* clip,
1958 float* scale_factor) {
1959 // Bare RenderWidgets don't support optimized plugin painting.
1960 return NULL;
1963 gfx::Vector2d RenderWidget::GetScrollOffset() {
1964 // Bare RenderWidgets don't support scroll offset.
1965 return gfx::Vector2d();
1968 void RenderWidget::SetHidden(bool hidden) {
1969 if (is_hidden_ == hidden)
1970 return;
1972 // The status has changed. Tell the RenderThread about it.
1973 is_hidden_ = hidden;
1974 if (is_hidden_)
1975 RenderThread::Get()->WidgetHidden();
1976 else
1977 RenderThread::Get()->WidgetRestored();
1980 void RenderWidget::WillToggleFullscreen() {
1981 if (!webwidget_)
1982 return;
1984 if (is_fullscreen_) {
1985 webwidget_->willExitFullScreen();
1986 } else {
1987 webwidget_->willEnterFullScreen();
1991 void RenderWidget::DidToggleFullscreen() {
1992 if (!webwidget_)
1993 return;
1995 if (is_fullscreen_) {
1996 webwidget_->didEnterFullScreen();
1997 } else {
1998 webwidget_->didExitFullScreen();
2002 void RenderWidget::SetBackground(const SkBitmap& background) {
2003 background_ = background;
2005 // Generate a full repaint.
2006 didInvalidateRect(gfx::Rect(size_.width(), size_.height()));
2009 bool RenderWidget::next_paint_is_resize_ack() const {
2010 return ViewHostMsg_UpdateRect_Flags::is_resize_ack(next_paint_flags_);
2013 bool RenderWidget::next_paint_is_restore_ack() const {
2014 return ViewHostMsg_UpdateRect_Flags::is_restore_ack(next_paint_flags_);
2017 void RenderWidget::set_next_paint_is_resize_ack() {
2018 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK;
2021 void RenderWidget::set_next_paint_is_restore_ack() {
2022 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK;
2025 void RenderWidget::set_next_paint_is_repaint_ack() {
2026 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK;
2029 static bool IsDateTimeInput(ui::TextInputType type) {
2030 return type == ui::TEXT_INPUT_TYPE_DATE ||
2031 type == ui::TEXT_INPUT_TYPE_DATE_TIME ||
2032 type == ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL ||
2033 type == ui::TEXT_INPUT_TYPE_MONTH ||
2034 type == ui::TEXT_INPUT_TYPE_TIME ||
2035 type == ui::TEXT_INPUT_TYPE_WEEK;
2038 void RenderWidget::UpdateTextInputState(ShowIme show_ime) {
2039 if (handling_ime_event_)
2040 return;
2041 bool show_ime_if_needed = (show_ime == SHOW_IME_IF_NEEDED);
2042 if (!show_ime_if_needed && !input_method_is_active_)
2043 return;
2044 ui::TextInputType new_type = GetTextInputType();
2045 if (IsDateTimeInput(new_type))
2046 return; // Not considered as a text input field in WebKit/Chromium.
2048 WebKit::WebTextInputInfo new_info;
2049 if (webwidget_)
2050 new_info = webwidget_->textInputInfo();
2052 bool new_can_compose_inline = CanComposeInline();
2054 // Only sends text input params if they are changed or if the ime should be
2055 // shown.
2056 if (show_ime_if_needed || (text_input_type_ != new_type
2057 || text_input_info_ != new_info
2058 || can_compose_inline_ != new_can_compose_inline)) {
2059 ViewHostMsg_TextInputState_Params p;
2060 p.type = new_type;
2061 p.value = new_info.value.utf8();
2062 p.selection_start = new_info.selectionStart;
2063 p.selection_end = new_info.selectionEnd;
2064 p.composition_start = new_info.compositionStart;
2065 p.composition_end = new_info.compositionEnd;
2066 p.can_compose_inline = new_can_compose_inline;
2067 p.show_ime_if_needed = show_ime_if_needed;
2068 Send(new ViewHostMsg_TextInputStateChanged(routing_id(), p));
2070 text_input_info_ = new_info;
2071 text_input_type_ = new_type;
2072 can_compose_inline_ = new_can_compose_inline;
2076 void RenderWidget::GetSelectionBounds(gfx::Rect* focus, gfx::Rect* anchor) {
2077 WebRect focus_webrect;
2078 WebRect anchor_webrect;
2079 webwidget_->selectionBounds(focus_webrect, anchor_webrect);
2080 *focus = focus_webrect;
2081 *anchor = anchor_webrect;
2084 void RenderWidget::UpdateSelectionBounds() {
2085 if (!webwidget_)
2086 return;
2088 ViewHostMsg_SelectionBounds_Params params;
2089 GetSelectionBounds(&params.anchor_rect, &params.focus_rect);
2090 if (selection_anchor_rect_ != params.anchor_rect ||
2091 selection_focus_rect_ != params.focus_rect) {
2092 selection_anchor_rect_ = params.anchor_rect;
2093 selection_focus_rect_ = params.focus_rect;
2094 webwidget_->selectionTextDirection(params.focus_dir, params.anchor_dir);
2095 params.is_anchor_first = webwidget_->isSelectionAnchorFirst();
2096 Send(new ViewHostMsg_SelectionBoundsChanged(routing_id_, params));
2099 std::vector<gfx::Rect> character_bounds;
2100 GetCompositionCharacterBounds(&character_bounds);
2101 UpdateCompositionInfo(composition_range_, character_bounds);
2104 bool RenderWidget::ShouldUpdateCompositionInfo(
2105 const ui::Range& range,
2106 const std::vector<gfx::Rect>& bounds) {
2107 if (composition_range_ != range)
2108 return true;
2109 if (bounds.size() != composition_character_bounds_.size())
2110 return true;
2111 for (size_t i = 0; i < bounds.size(); ++i) {
2112 if (bounds[i] != composition_character_bounds_[i])
2113 return true;
2115 return false;
2118 // Check WebKit::WebTextInputType and ui::TextInputType is kept in sync.
2119 COMPILE_ASSERT(int(WebKit::WebTextInputTypeNone) == \
2120 int(ui::TEXT_INPUT_TYPE_NONE), mismatching_enums);
2121 COMPILE_ASSERT(int(WebKit::WebTextInputTypeText) == \
2122 int(ui::TEXT_INPUT_TYPE_TEXT), mismatching_enums);
2123 COMPILE_ASSERT(int(WebKit::WebTextInputTypePassword) == \
2124 int(ui::TEXT_INPUT_TYPE_PASSWORD), mismatching_enums);
2125 COMPILE_ASSERT(int(WebKit::WebTextInputTypeSearch) == \
2126 int(ui::TEXT_INPUT_TYPE_SEARCH), mismatching_enums);
2127 COMPILE_ASSERT(int(WebKit::WebTextInputTypeEmail) == \
2128 int(ui::TEXT_INPUT_TYPE_EMAIL), mismatching_enums);
2129 COMPILE_ASSERT(int(WebKit::WebTextInputTypeNumber) == \
2130 int(ui::TEXT_INPUT_TYPE_NUMBER), mismatching_enums);
2131 COMPILE_ASSERT(int(WebKit::WebTextInputTypeTelephone) == \
2132 int(ui::TEXT_INPUT_TYPE_TELEPHONE), mismatching_enums);
2133 COMPILE_ASSERT(int(WebKit::WebTextInputTypeURL) == \
2134 int(ui::TEXT_INPUT_TYPE_URL), mismatching_enums);
2135 COMPILE_ASSERT(int(WebKit::WebTextInputTypeDate) == \
2136 int(ui::TEXT_INPUT_TYPE_DATE), mismatching_enum);
2137 COMPILE_ASSERT(int(WebKit::WebTextInputTypeDateTime) == \
2138 int(ui::TEXT_INPUT_TYPE_DATE_TIME), mismatching_enum);
2139 COMPILE_ASSERT(int(WebKit::WebTextInputTypeDateTimeLocal) == \
2140 int(ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL), mismatching_enum);
2141 COMPILE_ASSERT(int(WebKit::WebTextInputTypeMonth) == \
2142 int(ui::TEXT_INPUT_TYPE_MONTH), mismatching_enum);
2143 COMPILE_ASSERT(int(WebKit::WebTextInputTypeTime) == \
2144 int(ui::TEXT_INPUT_TYPE_TIME), mismatching_enum);
2145 COMPILE_ASSERT(int(WebKit::WebTextInputTypeWeek) == \
2146 int(ui::TEXT_INPUT_TYPE_WEEK), mismatching_enum);
2147 COMPILE_ASSERT(int(WebKit::WebTextInputTypeTextArea) == \
2148 int(ui::TEXT_INPUT_TYPE_TEXT_AREA), mismatching_enums);
2149 COMPILE_ASSERT(int(WebKit::WebTextInputTypeContentEditable) == \
2150 int(ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE), mismatching_enums);
2151 COMPILE_ASSERT(int(WebKit::WebTextInputTypeDateTimeField) == \
2152 int(ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD), mismatching_enums);
2154 ui::TextInputType RenderWidget::WebKitToUiTextInputType(
2155 WebKit::WebTextInputType type) {
2156 // Check the type is in the range representable by ui::TextInputType.
2157 DCHECK_LE(type, static_cast<int>(ui::TEXT_INPUT_TYPE_MAX)) <<
2158 "WebKit::WebTextInputType and ui::TextInputType not synchronized";
2159 return static_cast<ui::TextInputType>(type);
2162 ui::TextInputType RenderWidget::GetTextInputType() {
2163 if (webwidget_)
2164 return WebKitToUiTextInputType(webwidget_->textInputInfo().type);
2165 return ui::TEXT_INPUT_TYPE_NONE;
2168 void RenderWidget::GetCompositionCharacterBounds(
2169 std::vector<gfx::Rect>* bounds) {
2170 DCHECK(bounds);
2171 bounds->clear();
2174 bool RenderWidget::CanComposeInline() {
2175 return true;
2178 WebScreenInfo RenderWidget::screenInfo() {
2179 return screen_info_;
2182 float RenderWidget::deviceScaleFactor() {
2183 return device_scale_factor_;
2186 void RenderWidget::resetInputMethod() {
2187 if (!input_method_is_active_)
2188 return;
2190 // If the last text input type is not None, then we should finish any
2191 // ongoing composition regardless of the new text input type.
2192 if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE) {
2193 // If a composition text exists, then we need to let the browser process
2194 // to cancel the input method's ongoing composition session.
2195 if (webwidget_->confirmComposition())
2196 Send(new ViewHostMsg_ImeCancelComposition(routing_id()));
2199 // Send an updated IME range with the current caret rect.
2200 ui::Range range(ui::Range::InvalidRange());
2201 size_t location, length;
2202 if (webwidget_->caretOrSelectionRange(&location, &length)) {
2203 range.set_start(location);
2204 range.set_end(location + length);
2207 UpdateCompositionInfo(range, std::vector<gfx::Rect>());
2210 void RenderWidget::didHandleGestureEvent(
2211 const WebGestureEvent& event,
2212 bool event_cancelled) {
2213 #if defined(OS_ANDROID)
2214 if (event_cancelled)
2215 return;
2216 if (event.type == WebInputEvent::GestureTap ||
2217 event.type == WebInputEvent::GestureLongPress) {
2218 UpdateTextInputState(SHOW_IME_IF_NEEDED);
2220 #endif
2223 void RenderWidget::SchedulePluginMove(
2224 const webkit::npapi::WebPluginGeometry& move) {
2225 size_t i = 0;
2226 for (; i < plugin_window_moves_.size(); ++i) {
2227 if (plugin_window_moves_[i].window == move.window) {
2228 if (move.rects_valid) {
2229 plugin_window_moves_[i] = move;
2230 } else {
2231 plugin_window_moves_[i].visible = move.visible;
2233 break;
2237 if (i == plugin_window_moves_.size())
2238 plugin_window_moves_.push_back(move);
2241 void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) {
2242 for (WebPluginGeometryVector::iterator i = plugin_window_moves_.begin();
2243 i != plugin_window_moves_.end(); ++i) {
2244 if (i->window == window) {
2245 plugin_window_moves_.erase(i);
2246 break;
2251 void RenderWidget::GetRenderingStats(
2252 WebKit::WebRenderingStatsImpl& stats) const {
2253 if (compositor_)
2254 compositor_->GetRenderingStats(&stats.rendering_stats);
2256 stats.rendering_stats.animation_frame_count +=
2257 software_stats_.animation_frame_count;
2258 stats.rendering_stats.screen_frame_count +=
2259 software_stats_.screen_frame_count;
2260 stats.rendering_stats.total_paint_time +=
2261 software_stats_.total_paint_time;
2262 stats.rendering_stats.total_pixels_painted +=
2263 software_stats_.total_pixels_painted;
2266 bool RenderWidget::GetGpuRenderingStats(GpuRenderingStats* stats) const {
2267 GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel();
2268 if (!gpu_channel)
2269 return false;
2271 return gpu_channel->CollectRenderingStatsForSurface(surface_id(), stats);
2274 RenderWidgetCompositor* RenderWidget::compositor() const {
2275 return compositor_.get();
2278 void RenderWidget::BeginSmoothScroll(
2279 bool down,
2280 const SmoothScrollCompletionCallback& callback,
2281 int pixels_to_scroll,
2282 int mouse_event_x,
2283 int mouse_event_y) {
2284 DCHECK(!callback.is_null());
2286 ViewHostMsg_BeginSmoothScroll_Params params;
2287 params.scroll_down = down;
2288 params.pixels_to_scroll = pixels_to_scroll;
2289 params.mouse_event_x = mouse_event_x;
2290 params.mouse_event_y = mouse_event_y;
2292 Send(new ViewHostMsg_BeginSmoothScroll(routing_id_, params));
2293 pending_smooth_scroll_gesture_ = callback;
2296 bool RenderWidget::WillHandleMouseEvent(const WebKit::WebMouseEvent& event) {
2297 return false;
2300 bool RenderWidget::WillHandleGestureEvent(
2301 const WebKit::WebGestureEvent& event) {
2302 return false;
2305 void RenderWidget::hasTouchEventHandlers(bool has_handlers) {
2306 Send(new ViewHostMsg_HasTouchEventHandlers(routing_id_, has_handlers));
2309 bool RenderWidget::HasTouchEventHandlersAt(const gfx::Point& point) const {
2310 return true;
2313 WebGraphicsContext3DCommandBufferImpl* RenderWidget::CreateGraphicsContext3D(
2314 const WebKit::WebGraphicsContext3D::Attributes& attributes) {
2315 if (!webwidget_)
2316 return NULL;
2317 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
2318 new WebGraphicsContext3DCommandBufferImpl(
2319 surface_id(),
2320 GetURLForGraphicsContext3D(),
2321 RenderThreadImpl::current(),
2322 weak_ptr_factory_.GetWeakPtr()));
2324 if (!context->Initialize(
2325 attributes,
2326 false /* bind generates resources */,
2327 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE))
2328 return NULL;
2329 return context.release();
2332 } // namespace content