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"
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"
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
;
94 const char* GetEventName(WebInputEvent::Type type
) {
95 #define CASE_TYPE(t) case WebInputEvent::t: return #t
100 CASE_TYPE(MouseMove
);
101 CASE_TYPE(MouseEnter
);
102 CASE_TYPE(MouseLeave
);
103 CASE_TYPE(ContextMenu
);
104 CASE_TYPE(MouseWheel
);
105 CASE_TYPE(RawKeyDown
);
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
);
127 CASE_TYPE(TouchCancel
);
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";
140 RenderWidget::RenderWidget(WebKit::WebPopupType popup_type
,
141 const WebKit::WebScreenInfo
& screen_info
,
143 : routing_id_(MSG_ROUTING_NONE
),
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),
159 is_fullscreen_(false),
160 needs_repainting_on_restore_(false),
162 handling_input_event_(false),
163 handling_ime_event_(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) {
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();
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.
216 WebWidget
* RenderWidget::CreateWebWidget(RenderWidget
* render_widget
) {
217 switch (render_widget
->popup_type_
) {
218 case WebKit::WebPopupTypeNone
: // Nothing to create.
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
);
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
) {
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
);
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.
258 // The above Send can fail when the tab is closing.
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);
273 compositor_
->setSurfaceReady();
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
291 RenderProcess::current()->AddRefProcess();
294 bool RenderWidget::AllowPartialSwap() const {
298 bool RenderWidget::OnMessageReceived(const IPC::Message
& message
) {
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
)
328 IPC_MESSAGE_HANDLER(ViewMsg_Snapshot
, OnSnapshot
)
329 IPC_MESSAGE_UNHANDLED(handled
= false)
330 IPC_END_MESSAGE_MAP()
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
)) ||
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
,
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.
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;
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();
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() {
420 // Browser correspondence is no longer needed at this point.
421 if (routing_id_
!= MSG_ROUTING_NONE
) {
422 RenderThread::Get()->RemoveRoute(routing_id_
);
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
429 MessageLoop::current()->PostNonNestableTask(
430 FROM_HERE
, base::Bind(&RenderWidget::Close
, this));
432 // Balances the AddRef taken when we called AddRoute.
436 // Got a response from the browser after the renderer decided to create a new
438 void RenderWidget::OnCreatingNewAck() {
439 DCHECK(routing_id_
!= MSG_ROUTING_NONE
);
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
;
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.
478 void RenderWidget::OnWasShown(bool needs_repainting
) {
479 TRACE_EVENT0("renderer", "RenderWidget::OnWasShown");
480 // During shutdown we can just ignore this message.
487 if (!needs_repainting
&& !needs_repainting_on_restore_
)
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()));
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.
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");
535 // Notify subclasses that software rendering was flushed to the screen.
536 if (!is_accelerated_compositing_active_
) {
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())
553 GURL
RenderWidget::GetURLForGraphicsContext3D() {
557 bool RenderWidget::ForceCompositingModeEnabled() {
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
);
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(),
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.
619 num_swapbuffers_complete_pending_
= 0;
620 using_asynchronous_swapbuffers_
= false;
621 // Schedule another frame so the compositor learns about it.
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
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.
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");
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.
661 num_swapbuffers_complete_pending_
--;
663 // If update reply is still pending, then defer the update until that reply
665 if (update_reply_pending_
) {
666 TRACE_EVENT0("renderer", "EarlyOut_UpdateReplyPending");
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
674 if (!is_accelerated_compositing_active_
&& invalidation_task_posted_
) {
675 TRACE_EVENT0("renderer", "EarlyOut_AcceleratedCompositingOff");
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
683 if (!animation_update_pending_
&& !paint_aggregator_
.HasPendingUpdate()) {
684 TRACE_EVENT0("renderer", "EarlyOut_NoPendingUpdate");
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;
698 handling_input_event_
= false;
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(
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
)
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
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
,
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_
&&
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
);
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
);
802 handling_input_event_
= false;
804 if (!prevent_default
) {
805 if (WebInputEvent::isKeyboardEventType(input_event
->type
))
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() {
816 webwidget_
->mouseCaptureLost();
819 void RenderWidget::OnSetFocus(bool enable
) {
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
);
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()) {
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.
862 canvas
->scale(device_scale_factor_
, device_scale_factor_
);
863 canvas
->clipRect(gfx::RectToSkRect(rect
));
864 canvas
->drawPaint(paint
);
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
,
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
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
);
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
;
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
);
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
);
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;
957 paint
.setStyle(SkPaint::kStroke_Style
);
958 paint
.setColor(colors
[color_selector
++ % arraysize(colors
)]);
959 paint
.setStrokeWidth(1);
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");
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),
984 DoDeferredUpdateAndSendInputAck();
987 void RenderWidget::AnimateIfNeeded() {
988 if (!animation_update_pending_
)
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());
1013 double frame_begin_time
=
1014 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
1015 webwidget_
->animate(frame_begin_time
);
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
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() {
1052 if (pending_input_event_ack_
)
1053 Send(pending_input_event_ack_
.release());
1056 void RenderWidget::DoDeferredUpdate() {
1057 TRACE_EVENT0("renderer", "RenderWidget::DoDeferredUpdate");
1062 if (!init_complete_
) {
1063 TRACE_EVENT0("renderer", "EarlyOut_InitNotComplete");
1066 if (update_reply_pending_
) {
1067 TRACE_EVENT0("renderer", "EarlyOut_UpdateReplyPending");
1070 if (is_accelerated_compositing_active_
&&
1071 num_swapbuffers_complete_pending_
>= kMaxSwapBuffersPending
) {
1072 TRACE_EVENT0("renderer", "EarlyOut_MaxSwapBuffersPending");
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");
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();
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
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();
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",
1122 base::TimeDelta::FromMilliseconds(1),
1123 base::TimeDelta::FromMilliseconds(120),
1126 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.SoftwareDoDeferredUpdateDelay",
1128 base::TimeDelta::FromMilliseconds(1),
1129 base::TimeDelta::FromMilliseconds(120),
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(¤t_paint_buf_
,
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.
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
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
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_
)
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 ///////////////////////////////////////////////////////////////////////////////
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())
1304 paint_aggregator_
.InvalidateRect(damaged_rect
);
1306 // We may not need to schedule another call to DoDeferredUpdate.
1307 if (invalidation_task_posted_
)
1309 if (!paint_aggregator_
.HasPendingUpdate())
1311 if (update_reply_pending_
||
1312 num_swapbuffers_complete_pending_
>= kMaxSwapBuffersPending
)
1315 // When GPU rendering, combine pending animations and invalidations into
1317 if (is_accelerated_compositing_active_
&&
1318 animation_update_pending_
&&
1319 animation_timer_
.IsRunning())
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_
)
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())
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_
)
1350 if (!paint_aggregator_
.HasPendingUpdate())
1352 if (update_reply_pending_
||
1353 num_swapbuffers_complete_pending_
>= kMaxSwapBuffersPending
)
1356 // When GPU rendering, combine pending animations and invalidations into
1358 if (is_accelerated_compositing_active_
&&
1359 animation_update_pending_
&&
1360 animation_timer_
.IsRunning())
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
) {
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
,
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_
));
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_
));
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);
1449 compositor_
->setViewportSize(size_
, physical_backing_size_
);
1451 compositor_
->setSurfaceReady();
1454 WebKit::WebLayerTreeView
* RenderWidget::layerTreeView() {
1455 return compositor_
.get();
1458 void RenderWidget::suppressCompositorScheduling(bool enable
) {
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
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.
1496 void RenderWidget::didCompleteSwapBuffers() {
1497 TRACE_EVENT0("renderer", "RenderWidget::didCompleteSwapBuffers");
1499 // Notify subclasses threaded composited rendering was flushed to the screen.
1502 if (update_reply_pending_
)
1505 if (!next_paint_flags_
&&
1506 !need_update_rect_for_auto_resize_
&&
1507 !plugin_window_moves_
.size()) {
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() &&
1528 compositor_
->setNeedsRedraw();
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_
)
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
);
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_
));
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() {
1619 webwidget_
->willCloseLayerTreeView();
1620 compositor_
.reset();
1621 webwidget_
->close();
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
) {
1640 if (!RenderThreadImpl::current()->short_circuit_size_updates()) {
1641 Send(new ViewHostMsg_RequestMove(routing_id_
, pos
));
1642 SetPendingWindowRect(pos
);
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
;
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
))
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
) {
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
);
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
) {
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
,
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.
1773 ::CloseHandle(dib_handle
);
1774 #elif defined(OS_MACOSX)
1775 base::SharedMemory::CloseHandle(dib_handle
);
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
));
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()));
1816 // Reset bounds to what we actually received, but they should be the
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());
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
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());
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
) {
1846 if (OnSnapshotHelper(src_subrect
, &snapshot
)) {
1847 Send(new ViewHostMsg_Snapshot(routing_id(), true, snapshot
));
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())
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(),
1868 skia::RETURN_NULL_ON_FAILURE
));
1873 webwidget_
->layout();
1875 PaintRect(viewport_size
, viewport_size
.origin(), canvas
.get());
1878 const SkBitmap
& bitmap
= skia::GetTopDevice(*canvas
)->accessBitmap(false);
1879 if (!bitmap
.copyTo(snapshot
, SkBitmap::kARGB_8888_Config
))
1882 UMA_HISTOGRAM_TIMES("Renderer4.Snapshot",
1883 base::TimeTicks::Now() - beginning_time
);
1887 void RenderWidget::OnRepaint(gfx::Size size_to_paint
) {
1888 // During shutdown we can just ignore this message.
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
));
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
) {
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
);
1940 void RenderWidget::SetDeviceScaleFactor(float device_scale_factor
) {
1941 if (device_scale_factor_
== device_scale_factor
)
1944 device_scale_factor_
= device_scale_factor
;
1946 if (!is_accelerated_compositing_active_
) {
1947 didInvalidateRect(gfx::Rect(size_
.width(), size_
.height()));
1949 scheduleComposite();
1953 webkit::ppapi::PluginInstance
* RenderWidget::GetBitmapForOptimizedPluginPaint(
1954 const gfx::Rect
& paint_bounds
,
1956 gfx::Rect
* location
,
1958 float* scale_factor
) {
1959 // Bare RenderWidgets don't support optimized plugin painting.
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
)
1972 // The status has changed. Tell the RenderThread about it.
1973 is_hidden_
= hidden
;
1975 RenderThread::Get()->WidgetHidden();
1977 RenderThread::Get()->WidgetRestored();
1980 void RenderWidget::WillToggleFullscreen() {
1984 if (is_fullscreen_
) {
1985 webwidget_
->willExitFullScreen();
1987 webwidget_
->willEnterFullScreen();
1991 void RenderWidget::DidToggleFullscreen() {
1995 if (is_fullscreen_
) {
1996 webwidget_
->didEnterFullScreen();
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_
)
2041 bool show_ime_if_needed
= (show_ime
== SHOW_IME_IF_NEEDED
);
2042 if (!show_ime_if_needed
&& !input_method_is_active_
)
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
;
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
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
;
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() {
2088 ViewHostMsg_SelectionBounds_Params params
;
2089 GetSelectionBounds(¶ms
.anchor_rect
, ¶ms
.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
)
2109 if (bounds
.size() != composition_character_bounds_
.size())
2111 for (size_t i
= 0; i
< bounds
.size(); ++i
) {
2112 if (bounds
[i
] != composition_character_bounds_
[i
])
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() {
2164 return WebKitToUiTextInputType(webwidget_
->textInputInfo().type
);
2165 return ui::TEXT_INPUT_TYPE_NONE
;
2168 void RenderWidget::GetCompositionCharacterBounds(
2169 std::vector
<gfx::Rect
>* bounds
) {
2174 bool RenderWidget::CanComposeInline() {
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_
)
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
)
2216 if (event
.type
== WebInputEvent::GestureTap
||
2217 event
.type
== WebInputEvent::GestureLongPress
) {
2218 UpdateTextInputState(SHOW_IME_IF_NEEDED
);
2223 void RenderWidget::SchedulePluginMove(
2224 const webkit::npapi::WebPluginGeometry
& move
) {
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
;
2231 plugin_window_moves_
[i
].visible
= move
.visible
;
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
);
2251 void RenderWidget::GetRenderingStats(
2252 WebKit::WebRenderingStatsImpl
& stats
) const {
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();
2271 return gpu_channel
->CollectRenderingStatsForSurface(surface_id(), stats
);
2274 RenderWidgetCompositor
* RenderWidget::compositor() const {
2275 return compositor_
.get();
2278 void RenderWidget::BeginSmoothScroll(
2280 const SmoothScrollCompletionCallback
& callback
,
2281 int pixels_to_scroll
,
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
) {
2300 bool RenderWidget::WillHandleGestureEvent(
2301 const WebKit::WebGestureEvent
& event
) {
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 {
2313 WebGraphicsContext3DCommandBufferImpl
* RenderWidget::CreateGraphicsContext3D(
2314 const WebKit::WebGraphicsContext3D::Attributes
& attributes
) {
2317 scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
> context(
2318 new WebGraphicsContext3DCommandBufferImpl(
2320 GetURLForGraphicsContext3D(),
2321 RenderThreadImpl::current(),
2322 weak_ptr_factory_
.GetWeakPtr()));
2324 if (!context
->Initialize(
2326 false /* bind generates resources */,
2327 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE
))
2329 return context
.release();
2332 } // namespace content