IndexedDBFactory now ForceCloses databases.
[chromium-blink-merge.git] / content / renderer / render_widget.cc
blobe0f7ccc028b87ea618dd00caabf05b4df2e768d1
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/debug/trace_event_synthetic_delay.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/memory/singleton.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/metrics/histogram.h"
16 #include "base/stl_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "build/build_config.h"
19 #include "cc/base/switches.h"
20 #include "cc/debug/benchmark_instrumentation.h"
21 #include "cc/output/output_surface.h"
22 #include "cc/trees/layer_tree_host.h"
23 #include "content/child/npapi/webplugin.h"
24 #include "content/common/gpu/client/context_provider_command_buffer.h"
25 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
26 #include "content/common/gpu/gpu_process_launch_causes.h"
27 #include "content/common/input/synthetic_gesture_packet.h"
28 #include "content/common/input/web_input_event_traits.h"
29 #include "content/common/input_messages.h"
30 #include "content/common/swapped_out_messages.h"
31 #include "content/common/view_messages.h"
32 #include "content/public/common/content_switches.h"
33 #include "content/renderer/cursor_utils.h"
34 #include "content/renderer/external_popup_menu.h"
35 #include "content/renderer/gpu/compositor_output_surface.h"
36 #include "content/renderer/gpu/compositor_software_output_device.h"
37 #include "content/renderer/gpu/delegated_compositor_output_surface.h"
38 #include "content/renderer/gpu/mailbox_output_surface.h"
39 #include "content/renderer/gpu/render_widget_compositor.h"
40 #include "content/renderer/ime_event_guard.h"
41 #include "content/renderer/input/input_handler_manager.h"
42 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
43 #include "content/renderer/render_process.h"
44 #include "content/renderer/render_thread_impl.h"
45 #include "content/renderer/renderer_webkitplatformsupport_impl.h"
46 #include "content/renderer/resizing_mode_selector.h"
47 #include "ipc/ipc_sync_message.h"
48 #include "skia/ext/platform_canvas.h"
49 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
50 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
51 #include "third_party/WebKit/public/platform/WebRect.h"
52 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
53 #include "third_party/WebKit/public/platform/WebSize.h"
54 #include "third_party/WebKit/public/platform/WebString.h"
55 #include "third_party/WebKit/public/web/WebHelperPlugin.h"
56 #include "third_party/WebKit/public/web/WebPagePopup.h"
57 #include "third_party/WebKit/public/web/WebPopupMenu.h"
58 #include "third_party/WebKit/public/web/WebPopupMenuInfo.h"
59 #include "third_party/WebKit/public/web/WebRange.h"
60 #include "third_party/skia/include/core/SkShader.h"
61 #include "ui/base/ui_base_switches.h"
62 #include "ui/gfx/frame_time.h"
63 #include "ui/gfx/rect_conversions.h"
64 #include "ui/gfx/size_conversions.h"
65 #include "ui/gfx/skia_util.h"
66 #include "ui/gl/gl_switches.h"
67 #include "ui/surface/transport_dib.h"
68 #include "webkit/renderer/compositor_bindings/web_rendering_stats_impl.h"
70 #if defined(OS_ANDROID)
71 #include "base/android/sys_utils.h"
72 #include "content/renderer/android/synchronous_compositor_factory.h"
73 #endif
75 #if defined(OS_POSIX)
76 #include "ipc/ipc_channel_posix.h"
77 #include "third_party/skia/include/core/SkMallocPixelRef.h"
78 #include "third_party/skia/include/core/SkPixelRef.h"
79 #endif // defined(OS_POSIX)
81 #include "third_party/WebKit/public/web/WebWidget.h"
83 using blink::WebCompositionUnderline;
84 using blink::WebCursorInfo;
85 using blink::WebGestureEvent;
86 using blink::WebInputEvent;
87 using blink::WebKeyboardEvent;
88 using blink::WebMouseEvent;
89 using blink::WebMouseWheelEvent;
90 using blink::WebNavigationPolicy;
91 using blink::WebPagePopup;
92 using blink::WebPopupMenu;
93 using blink::WebPopupMenuInfo;
94 using blink::WebPopupType;
95 using blink::WebRange;
96 using blink::WebRect;
97 using blink::WebScreenInfo;
98 using blink::WebSize;
99 using blink::WebTextDirection;
100 using blink::WebTouchEvent;
101 using blink::WebTouchPoint;
102 using blink::WebVector;
103 using blink::WebWidget;
105 namespace {
107 typedef std::map<std::string, ui::TextInputMode> TextInputModeMap;
109 class TextInputModeMapSingleton {
110 public:
111 static TextInputModeMapSingleton* GetInstance() {
112 return Singleton<TextInputModeMapSingleton>::get();
114 TextInputModeMapSingleton() {
115 map_["verbatim"] = ui::TEXT_INPUT_MODE_VERBATIM;
116 map_["latin"] = ui::TEXT_INPUT_MODE_LATIN;
117 map_["latin-name"] = ui::TEXT_INPUT_MODE_LATIN_NAME;
118 map_["latin-prose"] = ui::TEXT_INPUT_MODE_LATIN_PROSE;
119 map_["full-width-latin"] = ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN;
120 map_["kana"] = ui::TEXT_INPUT_MODE_KANA;
121 map_["katakana"] = ui::TEXT_INPUT_MODE_KATAKANA;
122 map_["numeric"] = ui::TEXT_INPUT_MODE_NUMERIC;
123 map_["tel"] = ui::TEXT_INPUT_MODE_TEL;
124 map_["email"] = ui::TEXT_INPUT_MODE_EMAIL;
125 map_["url"] = ui::TEXT_INPUT_MODE_URL;
127 const TextInputModeMap& map() const { return map_; }
128 private:
129 TextInputModeMap map_;
131 friend struct DefaultSingletonTraits<TextInputModeMapSingleton>;
133 DISALLOW_COPY_AND_ASSIGN(TextInputModeMapSingleton);
136 ui::TextInputMode ConvertInputMode(const blink::WebString& input_mode) {
137 static TextInputModeMapSingleton* singleton =
138 TextInputModeMapSingleton::GetInstance();
139 TextInputModeMap::const_iterator it =
140 singleton->map().find(input_mode.utf8());
141 if (it == singleton->map().end())
142 return ui::TEXT_INPUT_MODE_DEFAULT;
143 return it->second;
146 // TODO(brianderson): Replace the hard-coded threshold with a fraction of
147 // the BeginMainFrame interval.
148 // 4166us will allow 1/4 of a 60Hz interval or 1/2 of a 120Hz interval to
149 // be spent in input hanlders before input starts getting throttled.
150 const int kInputHandlingTimeThrottlingThresholdMicroseconds = 4166;
152 } // namespace
154 namespace content {
156 // RenderWidget::ScreenMetricsEmulator ----------------------------------------
158 class RenderWidget::ScreenMetricsEmulator {
159 public:
160 ScreenMetricsEmulator(
161 RenderWidget* widget,
162 const gfx::Rect& device_rect,
163 const gfx::Rect& widget_rect,
164 float device_scale_factor,
165 bool fit_to_view);
166 virtual ~ScreenMetricsEmulator();
168 float scale() { return scale_; }
169 gfx::Point offset() { return offset_; }
170 gfx::Rect widget_rect() const { return widget_rect_; }
171 gfx::Rect original_screen_rect() const { return original_view_screen_rect_; }
173 void ChangeEmulationParams(
174 const gfx::Rect& device_rect,
175 const gfx::Rect& widget_rect,
176 float device_scale_factor,
177 bool fit_to_view);
179 // The following methods alter handlers' behavior for messages related to
180 // widget size and position.
181 void OnResizeMessage(const ViewMsg_Resize_Params& params);
182 void OnUpdateScreenRectsMessage(const gfx::Rect& view_screen_rect,
183 const gfx::Rect& window_screen_rect);
184 void OnShowContextMenu(ContextMenuParams* params);
186 private:
187 void Apply(float overdraw_bottom_height,
188 gfx::Rect resizer_rect, bool is_fullscreen);
190 RenderWidget* widget_;
192 // Parameters as passed by RenderWidget::EnableScreenMetricsEmulation.
193 gfx::Rect device_rect_;
194 gfx::Rect widget_rect_;
195 float device_scale_factor_;
196 bool fit_to_view_;
198 // The computed scale and offset used to fit widget into browser window.
199 float scale_;
200 gfx::Point offset_;
202 // Original values to restore back after emulation ends.
203 gfx::Size original_size_;
204 gfx::Size original_physical_backing_size_;
205 blink::WebScreenInfo original_screen_info_;
206 gfx::Rect original_view_screen_rect_;
207 gfx::Rect original_window_screen_rect_;
210 RenderWidget::ScreenMetricsEmulator::ScreenMetricsEmulator(
211 RenderWidget* widget,
212 const gfx::Rect& device_rect,
213 const gfx::Rect& widget_rect,
214 float device_scale_factor,
215 bool fit_to_view)
216 : widget_(widget),
217 device_rect_(device_rect),
218 widget_rect_(widget_rect),
219 device_scale_factor_(device_scale_factor),
220 fit_to_view_(fit_to_view),
221 scale_(1.f) {
222 original_size_ = widget_->size_;
223 original_physical_backing_size_ = widget_->physical_backing_size_;
224 original_screen_info_ = widget_->screen_info_;
225 original_view_screen_rect_ = widget_->view_screen_rect_;
226 original_window_screen_rect_ = widget_->window_screen_rect_;
227 Apply(widget_->overdraw_bottom_height_,
228 widget_->resizer_rect_, widget_->is_fullscreen_);
231 RenderWidget::ScreenMetricsEmulator::~ScreenMetricsEmulator() {
232 widget_->screen_info_ = original_screen_info_;
234 widget_->SetDeviceScaleFactor(original_screen_info_.deviceScaleFactor);
235 widget_->SetScreenMetricsEmulationParameters(0.f, gfx::Point(), 1.f);
236 widget_->view_screen_rect_ = original_view_screen_rect_;
237 widget_->window_screen_rect_ = original_window_screen_rect_;
238 widget_->Resize(original_size_, original_physical_backing_size_,
239 widget_->overdraw_bottom_height_, widget_->resizer_rect_,
240 widget_->is_fullscreen_, NO_RESIZE_ACK);
243 void RenderWidget::ScreenMetricsEmulator::ChangeEmulationParams(
244 const gfx::Rect& device_rect,
245 const gfx::Rect& widget_rect,
246 float device_scale_factor,
247 bool fit_to_view) {
248 device_rect_ = device_rect;
249 widget_rect_ = widget_rect;
250 device_scale_factor_ = device_scale_factor;
251 fit_to_view_ = fit_to_view;
252 Apply(widget_->overdraw_bottom_height_,
253 widget_->resizer_rect_, widget_->is_fullscreen_);
256 void RenderWidget::ScreenMetricsEmulator::Apply(
257 float overdraw_bottom_height, gfx::Rect resizer_rect, bool is_fullscreen) {
258 if (fit_to_view_) {
259 DCHECK(!original_size_.IsEmpty());
261 int width_with_gutter =
262 std::max(original_size_.width() - 2 * device_rect_.x(), 1);
263 int height_with_gutter =
264 std::max(original_size_.height() - 2 * device_rect_.y(), 1);
265 float width_ratio =
266 static_cast<float>(widget_rect_.width()) / width_with_gutter;
267 float height_ratio =
268 static_cast<float>(widget_rect_.height()) / height_with_gutter;
269 float ratio = std::max(1.0f, std::max(width_ratio, height_ratio));
270 scale_ = 1.f / ratio;
271 } else {
272 scale_ = 1.f;
275 // Center emulated view inside available view space.
276 offset_.set_x((original_size_.width() - scale_ * widget_rect_.width()) / 2);
277 offset_.set_y((original_size_.height() - scale_ * widget_rect_.height()) / 2);
279 widget_->screen_info_.rect = gfx::Rect(device_rect_.size());
280 widget_->screen_info_.availableRect = gfx::Rect(device_rect_.size());
281 widget_->screen_info_.deviceScaleFactor = device_scale_factor_;
283 // Pass three emulation parameters to the blink side:
284 // - we keep the real device scale factor in compositor to produce sharp image
285 // even when emulating different scale factor;
286 // - in order to fit into view, WebView applies offset and scale to the
287 // root layer.
288 widget_->SetScreenMetricsEmulationParameters(
289 original_screen_info_.deviceScaleFactor, offset_, scale_);
291 widget_->SetDeviceScaleFactor(device_scale_factor_);
292 widget_->view_screen_rect_ = widget_rect_;
293 widget_->window_screen_rect_ = widget_->screen_info_.availableRect;
295 gfx::Size physical_backing_size = gfx::ToCeiledSize(gfx::ScaleSize(
296 original_size_, original_screen_info_.deviceScaleFactor));
297 widget_->Resize(widget_rect_.size(), physical_backing_size,
298 overdraw_bottom_height, resizer_rect, is_fullscreen, NO_RESIZE_ACK);
301 void RenderWidget::ScreenMetricsEmulator::OnResizeMessage(
302 const ViewMsg_Resize_Params& params) {
303 bool need_ack = params.new_size != original_size_ &&
304 !params.new_size.IsEmpty() && !params.physical_backing_size.IsEmpty();
305 original_size_ = params.new_size;
306 original_physical_backing_size_ = params.physical_backing_size;
307 original_screen_info_ = params.screen_info;
308 Apply(params.overdraw_bottom_height, params.resizer_rect,
309 params.is_fullscreen);
311 if (need_ack) {
312 widget_->set_next_paint_is_resize_ack();
313 if (widget_->compositor_)
314 widget_->compositor_->SetNeedsRedrawRect(gfx::Rect(widget_->size_));
318 void RenderWidget::ScreenMetricsEmulator::OnUpdateScreenRectsMessage(
319 const gfx::Rect& view_screen_rect,
320 const gfx::Rect& window_screen_rect) {
321 original_view_screen_rect_ = view_screen_rect;
322 original_window_screen_rect_ = window_screen_rect;
325 void RenderWidget::ScreenMetricsEmulator::OnShowContextMenu(
326 ContextMenuParams* params) {
327 params->x *= scale_;
328 params->x += offset_.x();
329 params->y *= scale_;
330 params->y += offset_.y();
333 // RenderWidget ---------------------------------------------------------------
335 RenderWidget::RenderWidget(blink::WebPopupType popup_type,
336 const blink::WebScreenInfo& screen_info,
337 bool swapped_out,
338 bool hidden)
339 : routing_id_(MSG_ROUTING_NONE),
340 surface_id_(0),
341 webwidget_(NULL),
342 opener_id_(MSG_ROUTING_NONE),
343 init_complete_(false),
344 current_paint_buf_(NULL),
345 overdraw_bottom_height_(0.f),
346 next_paint_flags_(0),
347 filtered_time_per_frame_(0.0f),
348 update_reply_pending_(false),
349 auto_resize_mode_(false),
350 need_update_rect_for_auto_resize_(false),
351 using_asynchronous_swapbuffers_(false),
352 num_swapbuffers_complete_pending_(0),
353 did_show_(false),
354 is_hidden_(hidden),
355 is_fullscreen_(false),
356 needs_repainting_on_restore_(false),
357 has_focus_(false),
358 handling_input_event_(false),
359 handling_ime_event_(false),
360 handling_touchstart_event_(false),
361 closing_(false),
362 is_swapped_out_(swapped_out),
363 input_method_is_active_(false),
364 text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
365 text_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
366 can_compose_inline_(true),
367 popup_type_(popup_type),
368 pending_window_rect_count_(0),
369 suppress_next_char_events_(false),
370 is_accelerated_compositing_active_(false),
371 was_accelerated_compositing_ever_active_(false),
372 animation_update_pending_(false),
373 invalidation_task_posted_(false),
374 screen_info_(screen_info),
375 device_scale_factor_(screen_info_.deviceScaleFactor),
376 is_threaded_compositing_enabled_(false),
377 next_output_surface_id_(0),
378 #if defined(OS_ANDROID)
379 outstanding_ime_acks_(0),
380 #endif
381 popup_origin_scale_for_emulation_(0.f),
382 resizing_mode_selector_(new ResizingModeSelector()) {
383 if (!swapped_out)
384 RenderProcess::current()->AddRefProcess();
385 DCHECK(RenderThread::Get());
386 has_disable_gpu_vsync_switch_ = CommandLine::ForCurrentProcess()->HasSwitch(
387 switches::kDisableGpuVsync);
388 is_threaded_compositing_enabled_ =
389 CommandLine::ForCurrentProcess()->HasSwitch(
390 switches::kEnableThreadedCompositing);
392 legacy_software_mode_stats_ = cc::RenderingStatsInstrumentation::Create();
393 if (CommandLine::ForCurrentProcess()->HasSwitch(
394 switches::kEnableGpuBenchmarking))
395 legacy_software_mode_stats_->set_record_rendering_stats(true);
398 RenderWidget::~RenderWidget() {
399 DCHECK(!webwidget_) << "Leaking our WebWidget!";
400 STLDeleteElements(&updates_pending_swap_);
401 if (current_paint_buf_) {
402 if (RenderProcess::current()) {
403 // If the RenderProcess is already gone, it will have released all DIBs
404 // in its destructor anyway.
405 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
407 current_paint_buf_ = NULL;
409 // If we are swapped out, we have released already.
410 if (!is_swapped_out_ && RenderProcess::current())
411 RenderProcess::current()->ReleaseProcess();
414 // static
415 RenderWidget* RenderWidget::Create(int32 opener_id,
416 blink::WebPopupType popup_type,
417 const blink::WebScreenInfo& screen_info) {
418 DCHECK(opener_id != MSG_ROUTING_NONE);
419 scoped_refptr<RenderWidget> widget(
420 new RenderWidget(popup_type, screen_info, false, false));
421 if (widget->Init(opener_id)) { // adds reference on success.
422 return widget.get();
424 return NULL;
427 // static
428 WebWidget* RenderWidget::CreateWebWidget(RenderWidget* render_widget) {
429 switch (render_widget->popup_type_) {
430 case blink::WebPopupTypeNone: // Nothing to create.
431 break;
432 case blink::WebPopupTypeSelect:
433 case blink::WebPopupTypeSuggestion:
434 return WebPopupMenu::create(render_widget);
435 case blink::WebPopupTypePage:
436 return WebPagePopup::create(render_widget);
437 case blink::WebPopupTypeHelperPlugin:
438 return blink::WebHelperPlugin::create(render_widget);
439 default:
440 NOTREACHED();
442 return NULL;
445 bool RenderWidget::Init(int32 opener_id) {
446 return DoInit(opener_id,
447 RenderWidget::CreateWebWidget(this),
448 new ViewHostMsg_CreateWidget(opener_id, popup_type_,
449 &routing_id_, &surface_id_));
452 bool RenderWidget::DoInit(int32 opener_id,
453 WebWidget* web_widget,
454 IPC::SyncMessage* create_widget_message) {
455 DCHECK(!webwidget_);
457 if (opener_id != MSG_ROUTING_NONE)
458 opener_id_ = opener_id;
460 webwidget_ = web_widget;
462 bool result = RenderThread::Get()->Send(create_widget_message);
463 if (result) {
464 RenderThread::Get()->AddRoute(routing_id_, this);
465 // Take a reference on behalf of the RenderThread. This will be balanced
466 // when we receive ViewMsg_Close.
467 AddRef();
468 if (RenderThreadImpl::current()) {
469 RenderThreadImpl::current()->WidgetCreated();
470 if (is_hidden_)
471 RenderThreadImpl::current()->WidgetHidden();
473 return true;
474 } else {
475 // The above Send can fail when the tab is closing.
476 return false;
480 // This is used to complete pending inits and non-pending inits.
481 void RenderWidget::CompleteInit() {
482 DCHECK(routing_id_ != MSG_ROUTING_NONE);
484 init_complete_ = true;
486 if (webwidget_ && is_threaded_compositing_enabled_) {
487 webwidget_->enterForceCompositingMode(true);
489 if (compositor_) {
490 compositor_->setSurfaceReady();
492 DoDeferredUpdate();
494 Send(new ViewHostMsg_RenderViewReady(routing_id_));
497 void RenderWidget::SetSwappedOut(bool is_swapped_out) {
498 // We should only toggle between states.
499 DCHECK(is_swapped_out_ != is_swapped_out);
500 is_swapped_out_ = is_swapped_out;
502 // If we are swapping out, we will call ReleaseProcess, allowing the process
503 // to exit if all of its RenderViews are swapped out. We wait until the
504 // WasSwappedOut call to do this, to avoid showing the sad tab.
505 // If we are swapping in, we call AddRefProcess to prevent the process from
506 // exiting.
507 if (!is_swapped_out)
508 RenderProcess::current()->AddRefProcess();
511 bool RenderWidget::AllowPartialSwap() const {
512 return true;
515 bool RenderWidget::UsingSynchronousRendererCompositor() const {
516 #if defined(OS_ANDROID)
517 return SynchronousCompositorFactory::GetInstance() != NULL;
518 #else
519 return false;
520 #endif
523 void RenderWidget::EnableScreenMetricsEmulation(
524 const gfx::Rect& device_rect,
525 const gfx::Rect& widget_rect,
526 float device_scale_factor,
527 bool fit_to_view) {
528 if (!screen_metrics_emulator_) {
529 screen_metrics_emulator_.reset(new ScreenMetricsEmulator(this,
530 device_rect, widget_rect, device_scale_factor, fit_to_view));
531 } else {
532 screen_metrics_emulator_->ChangeEmulationParams(device_rect,
533 widget_rect, device_scale_factor, fit_to_view);
537 void RenderWidget::DisableScreenMetricsEmulation() {
538 screen_metrics_emulator_.reset();
541 void RenderWidget::SetPopupOriginAdjustmentsForEmulation(
542 ScreenMetricsEmulator* emulator) {
543 popup_origin_scale_for_emulation_ = emulator->scale();
544 popup_view_origin_for_emulation_ = emulator->widget_rect().origin();
545 popup_screen_origin_for_emulation_ = gfx::Point(
546 emulator->original_screen_rect().origin().x() + emulator->offset().x(),
547 emulator->original_screen_rect().origin().y() + emulator->offset().y());
550 void RenderWidget::SetScreenMetricsEmulationParameters(
551 float device_scale_factor,
552 const gfx::Point& root_layer_offset,
553 float root_layer_scale) {
554 // This is only supported in RenderView.
555 NOTREACHED();
558 void RenderWidget::SetExternalPopupOriginAdjustmentsForEmulation(
559 ExternalPopupMenu* popup, ScreenMetricsEmulator* emulator) {
560 popup->SetOriginScaleAndOffsetForEmulation(
561 emulator->scale(), emulator->offset());
564 void RenderWidget::OnShowHostContextMenu(ContextMenuParams* params) {
565 if (screen_metrics_emulator_)
566 screen_metrics_emulator_->OnShowContextMenu(params);
569 void RenderWidget::ScheduleCompositeWithForcedRedraw() {
570 if (compositor_) {
571 // Regardless of whether threaded compositing is enabled, always
572 // use this mechanism to force the compositor to redraw. However,
573 // the invalidation code path below is still needed for the
574 // non-threaded case.
575 compositor_->SetNeedsForcedRedraw();
577 scheduleComposite();
580 bool RenderWidget::OnMessageReceived(const IPC::Message& message) {
581 bool handled = true;
582 IPC_BEGIN_MESSAGE_MAP(RenderWidget, message)
583 IPC_MESSAGE_HANDLER(InputMsg_HandleInputEvent, OnHandleInputEvent)
584 IPC_MESSAGE_HANDLER(InputMsg_CursorVisibilityChange,
585 OnCursorVisibilityChange)
586 IPC_MESSAGE_HANDLER(InputMsg_MouseCaptureLost, OnMouseCaptureLost)
587 IPC_MESSAGE_HANDLER(InputMsg_SetFocus, OnSetFocus)
588 IPC_MESSAGE_HANDLER(InputMsg_SyntheticGestureCompleted,
589 OnSyntheticGestureCompleted)
590 IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
591 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
592 IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize)
593 IPC_MESSAGE_HANDLER(ViewMsg_ChangeResizeRect, OnChangeResizeRect)
594 IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden)
595 IPC_MESSAGE_HANDLER(ViewMsg_WasShown, OnWasShown)
596 IPC_MESSAGE_HANDLER(ViewMsg_WasSwappedOut, OnWasSwappedOut)
597 IPC_MESSAGE_HANDLER(ViewMsg_UpdateRect_ACK, OnUpdateRectAck)
598 IPC_MESSAGE_HANDLER(ViewMsg_SwapBuffers_ACK, OnSwapBuffersComplete)
599 IPC_MESSAGE_HANDLER(ViewMsg_SetInputMethodActive, OnSetInputMethodActive)
600 IPC_MESSAGE_HANDLER(ViewMsg_CandidateWindowShown, OnCandidateWindowShown)
601 IPC_MESSAGE_HANDLER(ViewMsg_CandidateWindowUpdated,
602 OnCandidateWindowUpdated)
603 IPC_MESSAGE_HANDLER(ViewMsg_CandidateWindowHidden, OnCandidateWindowHidden)
604 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition)
605 IPC_MESSAGE_HANDLER(ViewMsg_ImeConfirmComposition, OnImeConfirmComposition)
606 IPC_MESSAGE_HANDLER(ViewMsg_PaintAtSize, OnPaintAtSize)
607 IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnRepaint)
608 IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection)
609 IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck)
610 IPC_MESSAGE_HANDLER(ViewMsg_UpdateScreenRects, OnUpdateScreenRects)
611 #if defined(OS_ANDROID)
612 IPC_MESSAGE_HANDLER(ViewMsg_ShowImeIfNeeded, OnShowImeIfNeeded)
613 IPC_MESSAGE_HANDLER(ViewMsg_ImeEventAck, OnImeEventAck)
614 #endif
615 IPC_MESSAGE_HANDLER(ViewMsg_Snapshot, OnSnapshot)
616 IPC_MESSAGE_HANDLER(ViewMsg_SetBrowserRenderingStats,
617 OnSetBrowserRenderingStats)
618 IPC_MESSAGE_UNHANDLED(handled = false)
619 IPC_END_MESSAGE_MAP()
620 return handled;
623 bool RenderWidget::Send(IPC::Message* message) {
624 // Don't send any messages after the browser has told us to close, and filter
625 // most outgoing messages while swapped out.
626 if ((is_swapped_out_ &&
627 !SwappedOutMessages::CanSendWhileSwappedOut(message)) ||
628 closing_) {
629 delete message;
630 return false;
633 // If given a messsage without a routing ID, then assign our routing ID.
634 if (message->routing_id() == MSG_ROUTING_NONE)
635 message->set_routing_id(routing_id_);
637 return RenderThread::Get()->Send(message);
640 void RenderWidget::Resize(const gfx::Size& new_size,
641 const gfx::Size& physical_backing_size,
642 float overdraw_bottom_height,
643 const gfx::Rect& resizer_rect,
644 bool is_fullscreen,
645 ResizeAck resize_ack) {
646 if (resizing_mode_selector_->NeverUsesSynchronousResize()) {
647 // A resize ack shouldn't be requested if we have not ACK'd the previous
648 // one.
649 DCHECK(resize_ack != SEND_RESIZE_ACK || !next_paint_is_resize_ack());
650 DCHECK(resize_ack == SEND_RESIZE_ACK || resize_ack == NO_RESIZE_ACK);
653 // Ignore this during shutdown.
654 if (!webwidget_)
655 return;
657 if (compositor_) {
658 compositor_->setViewportSize(new_size, physical_backing_size);
659 compositor_->SetOverdrawBottomHeight(overdraw_bottom_height);
662 physical_backing_size_ = physical_backing_size;
663 overdraw_bottom_height_ = overdraw_bottom_height;
664 resizer_rect_ = resizer_rect;
666 // NOTE: We may have entered fullscreen mode without changing our size.
667 bool fullscreen_change = is_fullscreen_ != is_fullscreen;
668 if (fullscreen_change)
669 WillToggleFullscreen();
670 is_fullscreen_ = is_fullscreen;
672 if (size_ != new_size) {
673 // TODO(darin): We should not need to reset this here.
674 needs_repainting_on_restore_ = false;
676 size_ = new_size;
678 paint_aggregator_.ClearPendingUpdate();
680 // When resizing, we want to wait to paint before ACK'ing the resize. This
681 // ensures that we only resize as fast as we can paint. We only need to
682 // send an ACK if we are resized to a non-empty rect.
683 webwidget_->resize(new_size);
685 if (resizing_mode_selector_->NeverUsesSynchronousResize()) {
686 // Resize should have caused an invalidation of the entire view.
687 DCHECK(new_size.IsEmpty() || is_accelerated_compositing_active_ ||
688 paint_aggregator_.HasPendingUpdate());
690 } else if (!resizing_mode_selector_->is_synchronous_mode()) {
691 resize_ack = NO_RESIZE_ACK;
694 if (new_size.IsEmpty() || physical_backing_size.IsEmpty()) {
695 // For empty size or empty physical_backing_size, there is no next paint
696 // (along with which to send the ack) until they are set to non-empty.
697 resize_ack = NO_RESIZE_ACK;
700 // Send the Resize_ACK flag once we paint again if requested.
701 if (resize_ack == SEND_RESIZE_ACK)
702 set_next_paint_is_resize_ack();
704 if (fullscreen_change)
705 DidToggleFullscreen();
707 // If a resize ack is requested and it isn't set-up, then no more resizes will
708 // come in and in general things will go wrong.
709 DCHECK(resize_ack != SEND_RESIZE_ACK || next_paint_is_resize_ack());
712 void RenderWidget::ResizeSynchronously(const gfx::Rect& new_position) {
713 Resize(new_position.size(), new_position.size(), overdraw_bottom_height_,
714 gfx::Rect(), is_fullscreen_, NO_RESIZE_ACK);
715 view_screen_rect_ = new_position;
716 window_screen_rect_ = new_position;
717 if (!did_show_)
718 initial_pos_ = new_position;
721 void RenderWidget::OnClose() {
722 if (closing_)
723 return;
724 closing_ = true;
726 // Browser correspondence is no longer needed at this point.
727 if (routing_id_ != MSG_ROUTING_NONE) {
728 if (RenderThreadImpl::current())
729 RenderThreadImpl::current()->WidgetDestroyed();
730 RenderThread::Get()->RemoveRoute(routing_id_);
731 SetHidden(false);
734 // If there is a Send call on the stack, then it could be dangerous to close
735 // now. Post a task that only gets invoked when there are no nested message
736 // loops.
737 base::MessageLoop::current()->PostNonNestableTask(
738 FROM_HERE, base::Bind(&RenderWidget::Close, this));
740 // Balances the AddRef taken when we called AddRoute.
741 Release();
744 // Got a response from the browser after the renderer decided to create a new
745 // view.
746 void RenderWidget::OnCreatingNewAck() {
747 DCHECK(routing_id_ != MSG_ROUTING_NONE);
749 CompleteInit();
752 void RenderWidget::OnResize(const ViewMsg_Resize_Params& params) {
753 if (resizing_mode_selector_->ShouldAbortOnResize(this, params))
754 return;
756 if (screen_metrics_emulator_) {
757 screen_metrics_emulator_->OnResizeMessage(params);
758 return;
761 screen_info_ = params.screen_info;
762 SetDeviceScaleFactor(screen_info_.deviceScaleFactor);
763 Resize(params.new_size, params.physical_backing_size,
764 params.overdraw_bottom_height, params.resizer_rect,
765 params.is_fullscreen, SEND_RESIZE_ACK);
768 void RenderWidget::OnChangeResizeRect(const gfx::Rect& resizer_rect) {
769 if (resizer_rect_ != resizer_rect) {
770 gfx::Rect view_rect(size_);
772 gfx::Rect old_damage_rect = gfx::IntersectRects(view_rect, resizer_rect_);
773 if (!old_damage_rect.IsEmpty())
774 paint_aggregator_.InvalidateRect(old_damage_rect);
776 gfx::Rect new_damage_rect = gfx::IntersectRects(view_rect, resizer_rect);
777 if (!new_damage_rect.IsEmpty())
778 paint_aggregator_.InvalidateRect(new_damage_rect);
780 resizer_rect_ = resizer_rect;
782 if (webwidget_)
783 webwidget_->didChangeWindowResizerRect();
787 void RenderWidget::OnWasHidden() {
788 TRACE_EVENT0("renderer", "RenderWidget::OnWasHidden");
789 // Go into a mode where we stop generating paint and scrolling events.
790 SetHidden(true);
793 void RenderWidget::OnWasShown(bool needs_repainting) {
794 TRACE_EVENT0("renderer", "RenderWidget::OnWasShown");
795 // During shutdown we can just ignore this message.
796 if (!webwidget_)
797 return;
799 // See OnWasHidden
800 SetHidden(false);
802 if (!needs_repainting && !needs_repainting_on_restore_)
803 return;
804 needs_repainting_on_restore_ = false;
806 // Tag the next paint as a restore ack, which is picked up by
807 // DoDeferredUpdate when it sends out the next PaintRect message.
808 set_next_paint_is_restore_ack();
810 // Generate a full repaint.
811 if (!is_accelerated_compositing_active_) {
812 didInvalidateRect(gfx::Rect(size_.width(), size_.height()));
813 } else {
814 if (compositor_)
815 compositor_->SetNeedsForcedRedraw();
816 scheduleComposite();
820 void RenderWidget::OnWasSwappedOut() {
821 // If we have been swapped out and no one else is using this process,
822 // it's safe to exit now. If we get swapped back in, we will call
823 // AddRefProcess in SetSwappedOut.
824 if (is_swapped_out_)
825 RenderProcess::current()->ReleaseProcess();
828 void RenderWidget::OnRequestMoveAck() {
829 DCHECK(pending_window_rect_count_);
830 pending_window_rect_count_--;
833 void RenderWidget::OnUpdateRectAck() {
834 TRACE_EVENT0("renderer", "RenderWidget::OnUpdateRectAck");
835 DCHECK(update_reply_pending_);
836 update_reply_pending_ = false;
838 // If we sent an UpdateRect message with a zero-sized bitmap, then we should
839 // have no current paint buffer.
840 if (current_paint_buf_) {
841 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
842 current_paint_buf_ = NULL;
845 // If swapbuffers is still pending, then defer the update until the
846 // swapbuffers occurs.
847 if (num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) {
848 TRACE_EVENT0("renderer", "EarlyOut_SwapStillPending");
849 return;
852 // Notify subclasses that software rendering was flushed to the screen.
853 if (!is_accelerated_compositing_active_) {
854 DidFlushPaint();
857 // Continue painting if necessary...
858 DoDeferredUpdateAndSendInputAck();
861 bool RenderWidget::SupportsAsynchronousSwapBuffers() {
862 // Contexts using the command buffer support asynchronous swapbuffers.
863 // See RenderWidget::CreateOutputSurface().
864 if (RenderThreadImpl::current()->compositor_message_loop_proxy().get())
865 return false;
867 return true;
870 GURL RenderWidget::GetURLForGraphicsContext3D() {
871 return GURL();
874 bool RenderWidget::ForceCompositingModeEnabled() {
875 return false;
878 scoped_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface(bool fallback) {
880 #if defined(OS_ANDROID)
881 if (SynchronousCompositorFactory* factory =
882 SynchronousCompositorFactory::GetInstance()) {
883 return factory->CreateOutputSurface(routing_id());
885 #endif
887 // Explicitly disable antialiasing for the compositor. As of the time of
888 // this writing, the only platform that supported antialiasing for the
889 // compositor was Mac OS X, because the on-screen OpenGL context creation
890 // code paths on Windows and Linux didn't yet have multisampling support.
891 // Mac OS X essentially always behaves as though it's rendering offscreen.
892 // Multisampling has a heavy cost especially on devices with relatively low
893 // fill rate like most notebooks, and the Mac implementation would need to
894 // be optimized to resolve directly into the IOSurface shared between the
895 // GPU and browser processes. For these reasons and to avoid platform
896 // disparities we explicitly disable antialiasing.
897 blink::WebGraphicsContext3D::Attributes attributes;
898 attributes.antialias = false;
899 attributes.shareResources = true;
900 attributes.noAutomaticFlushes = true;
901 attributes.depth = false;
902 attributes.stencil = false;
904 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
905 scoped_refptr<ContextProviderCommandBuffer> context_provider;
906 if (!fallback) {
907 context_provider = ContextProviderCommandBuffer::Create(
908 CreateGraphicsContext3D(attributes),
909 "RenderCompositor");
912 uint32 output_surface_id = next_output_surface_id_++;
913 if (!context_provider.get()) {
914 if (!command_line.HasSwitch(switches::kEnableSoftwareCompositing))
915 return scoped_ptr<cc::OutputSurface>();
917 scoped_ptr<cc::SoftwareOutputDevice> software_device(
918 new CompositorSoftwareOutputDevice());
920 return scoped_ptr<cc::OutputSurface>(new CompositorOutputSurface(
921 routing_id(),
922 output_surface_id,
923 NULL,
924 software_device.Pass(),
925 true));
928 if (command_line.HasSwitch(switches::kEnableDelegatedRenderer) &&
929 !command_line.HasSwitch(switches::kDisableDelegatedRenderer)) {
930 DCHECK(is_threaded_compositing_enabled_);
931 return scoped_ptr<cc::OutputSurface>(
932 new DelegatedCompositorOutputSurface(
933 routing_id(),
934 output_surface_id,
935 context_provider,
936 scoped_ptr<cc::SoftwareOutputDevice>()));
938 if (command_line.HasSwitch(cc::switches::kCompositeToMailbox)) {
939 DCHECK(is_threaded_compositing_enabled_);
940 cc::ResourceFormat format = cc::RGBA_8888;
941 #if defined(OS_ANDROID)
942 if (base::android::SysUtils::IsLowEndDevice())
943 format = cc::RGB_565;
944 #endif
945 return scoped_ptr<cc::OutputSurface>(
946 new MailboxOutputSurface(
947 routing_id(),
948 output_surface_id,
949 context_provider,
950 scoped_ptr<cc::SoftwareOutputDevice>(),
951 format));
953 bool use_swap_compositor_frame_message = false;
954 return scoped_ptr<cc::OutputSurface>(
955 new CompositorOutputSurface(
956 routing_id(),
957 output_surface_id,
958 context_provider,
959 scoped_ptr<cc::SoftwareOutputDevice>(),
960 use_swap_compositor_frame_message));
963 void RenderWidget::OnSwapBuffersAborted() {
964 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersAborted");
965 while (!updates_pending_swap_.empty()) {
966 ViewHostMsg_UpdateRect* msg = updates_pending_swap_.front();
967 updates_pending_swap_.pop_front();
968 // msg can be NULL if the swap doesn't correspond to an DoDeferredUpdate
969 // compositing pass, hence doesn't require an UpdateRect message.
970 if (msg)
971 Send(msg);
973 num_swapbuffers_complete_pending_ = 0;
974 using_asynchronous_swapbuffers_ = false;
975 // Schedule another frame so the compositor learns about it.
976 scheduleComposite();
979 void RenderWidget::OnSwapBuffersPosted() {
980 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersPosted");
982 if (using_asynchronous_swapbuffers_) {
983 ViewHostMsg_UpdateRect* msg = NULL;
984 // pending_update_params_ can be NULL if the swap doesn't correspond to an
985 // DoDeferredUpdate compositing pass, hence doesn't require an UpdateRect
986 // message.
987 if (pending_update_params_) {
988 msg = new ViewHostMsg_UpdateRect(routing_id_, *pending_update_params_);
989 pending_update_params_.reset();
991 updates_pending_swap_.push_back(msg);
992 num_swapbuffers_complete_pending_++;
996 void RenderWidget::OnSwapBuffersComplete() {
997 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersComplete");
999 // Notify subclasses that composited rendering was flushed to the screen.
1000 DidFlushPaint();
1002 // When compositing deactivates, we reset the swapbuffers pending count. The
1003 // swapbuffers acks may still arrive, however.
1004 if (num_swapbuffers_complete_pending_ == 0) {
1005 TRACE_EVENT0("renderer", "EarlyOut_ZeroSwapbuffersPending");
1006 return;
1008 DCHECK(!updates_pending_swap_.empty());
1009 ViewHostMsg_UpdateRect* msg = updates_pending_swap_.front();
1010 updates_pending_swap_.pop_front();
1011 // msg can be NULL if the swap doesn't correspond to an DoDeferredUpdate
1012 // compositing pass, hence doesn't require an UpdateRect message.
1013 if (msg)
1014 Send(msg);
1015 num_swapbuffers_complete_pending_--;
1017 // If update reply is still pending, then defer the update until that reply
1018 // occurs.
1019 if (update_reply_pending_) {
1020 TRACE_EVENT0("renderer", "EarlyOut_UpdateReplyPending");
1021 return;
1024 // If we are not accelerated rendering, then this is a stale swapbuffers from
1025 // when we were previously rendering. However, if an invalidation task is not
1026 // posted, there may be software rendering work pending. In that case, don't
1027 // early out.
1028 if (!is_accelerated_compositing_active_ && invalidation_task_posted_) {
1029 TRACE_EVENT0("renderer", "EarlyOut_AcceleratedCompositingOff");
1030 return;
1033 // Do not call DoDeferredUpdate unless there's animation work to be done or
1034 // a real invalidation. This prevents rendering in response to a swapbuffers
1035 // callback coming back after we've navigated away from the page that
1036 // generated it.
1037 if (!animation_update_pending_ && !paint_aggregator_.HasPendingUpdate()) {
1038 TRACE_EVENT0("renderer", "EarlyOut_NoPendingUpdate");
1039 return;
1042 // Continue painting if necessary...
1043 DoDeferredUpdateAndSendInputAck();
1046 void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event,
1047 ui::LatencyInfo latency_info,
1048 bool is_keyboard_shortcut) {
1049 handling_input_event_ = true;
1050 if (!input_event) {
1051 handling_input_event_ = false;
1052 return;
1055 base::TimeTicks start_time;
1056 if (base::TimeTicks::IsHighResNowFastAndReliable())
1057 start_time = base::TimeTicks::HighResNow();
1059 const char* const event_name =
1060 WebInputEventTraits::GetName(input_event->type);
1061 TRACE_EVENT1("renderer", "RenderWidget::OnHandleInputEvent",
1062 "event", event_name);
1063 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("blink.HandleInputEvent");
1065 scoped_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor;
1067 if (compositor_) {
1068 latency_info_swap_promise_monitor =
1069 compositor_->CreateLatencyInfoSwapPromiseMonitor(&latency_info).Pass();
1070 } else {
1071 latency_info_.push_back(latency_info);
1074 base::TimeDelta now = base::TimeDelta::FromInternalValue(
1075 base::TimeTicks::Now().ToInternalValue());
1077 int64 delta = static_cast<int64>(
1078 (now.InSecondsF() - input_event->timeStampSeconds) *
1079 base::Time::kMicrosecondsPerSecond);
1080 UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Renderer", delta, 0, 1000000, 100);
1081 base::HistogramBase* counter_for_type =
1082 base::Histogram::FactoryGet(
1083 base::StringPrintf("Event.Latency.Renderer.%s", event_name),
1085 1000000,
1086 100,
1087 base::HistogramBase::kUmaTargetedHistogramFlag);
1088 counter_for_type->Add(delta);
1090 bool prevent_default = false;
1091 if (WebInputEvent::isMouseEventType(input_event->type)) {
1092 const WebMouseEvent& mouse_event =
1093 *static_cast<const WebMouseEvent*>(input_event);
1094 TRACE_EVENT2("renderer", "HandleMouseMove",
1095 "x", mouse_event.x, "y", mouse_event.y);
1096 prevent_default = WillHandleMouseEvent(mouse_event);
1099 if (WebInputEvent::isKeyboardEventType(input_event->type)) {
1100 const WebKeyboardEvent& key_event =
1101 *static_cast<const WebKeyboardEvent*>(input_event);
1102 prevent_default = WillHandleKeyEvent(key_event);
1105 if (WebInputEvent::isGestureEventType(input_event->type)) {
1106 const WebGestureEvent& gesture_event =
1107 *static_cast<const WebGestureEvent*>(input_event);
1108 prevent_default = prevent_default || WillHandleGestureEvent(gesture_event);
1111 if (input_event->type == WebInputEvent::GestureTap ||
1112 input_event->type == WebInputEvent::GestureLongPress)
1113 resetInputMethod();
1115 if (input_event->type == WebInputEvent::TouchStart)
1116 handling_touchstart_event_ = true;
1118 bool processed = prevent_default;
1119 if (input_event->type != WebInputEvent::Char || !suppress_next_char_events_) {
1120 suppress_next_char_events_ = false;
1121 if (!processed && webwidget_)
1122 processed = webwidget_->handleInputEvent(*input_event);
1125 handling_touchstart_event_ = false;
1127 // If this RawKeyDown event corresponds to a browser keyboard shortcut and
1128 // it's not processed by webkit, then we need to suppress the upcoming Char
1129 // events.
1130 if (!processed && is_keyboard_shortcut)
1131 suppress_next_char_events_ = true;
1133 InputEventAckState ack_result = processed ?
1134 INPUT_EVENT_ACK_STATE_CONSUMED : INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
1135 if (!processed && input_event->type == WebInputEvent::TouchStart) {
1136 const WebTouchEvent& touch_event =
1137 *static_cast<const WebTouchEvent*>(input_event);
1138 // Hit-test for all the pressed touch points. If there is a touch-handler
1139 // for any of the touch points, then the renderer should continue to receive
1140 // touch events.
1141 ack_result = INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
1142 for (size_t i = 0; i < touch_event.touchesLength; ++i) {
1143 if (touch_event.touches[i].state == WebTouchPoint::StatePressed &&
1144 HasTouchEventHandlersAt(touch_event.touches[i].position)) {
1145 ack_result = INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
1146 break;
1151 bool event_type_can_be_rate_limited =
1152 input_event->type == WebInputEvent::MouseMove ||
1153 input_event->type == WebInputEvent::MouseWheel ||
1154 input_event->type == WebInputEvent::TouchMove;
1156 bool frame_pending = paint_aggregator_.HasPendingUpdate();
1157 if (is_accelerated_compositing_active_) {
1158 frame_pending = compositor_ &&
1159 compositor_->BeginMainFrameRequested();
1162 // If we don't have a fast and accurate HighResNow, we assume the input
1163 // handlers are heavy and rate limit them.
1164 bool rate_limiting_wanted = true;
1165 if (base::TimeTicks::IsHighResNowFastAndReliable()) {
1166 base::TimeTicks end_time = base::TimeTicks::HighResNow();
1167 total_input_handling_time_this_frame_ += (end_time - start_time);
1168 rate_limiting_wanted =
1169 total_input_handling_time_this_frame_.InMicroseconds() >
1170 kInputHandlingTimeThrottlingThresholdMicroseconds;
1173 if (!WebInputEventTraits::IgnoresAckDisposition(input_event->type)) {
1174 scoped_ptr<IPC::Message> response(
1175 new InputHostMsg_HandleInputEvent_ACK(routing_id_,
1176 input_event->type,
1177 ack_result,
1178 latency_info));
1179 if (rate_limiting_wanted && event_type_can_be_rate_limited &&
1180 frame_pending && !is_hidden_) {
1181 // We want to rate limit the input events in this case, so we'll wait for
1182 // painting to finish before ACKing this message.
1183 TRACE_EVENT_INSTANT0("renderer",
1184 "RenderWidget::OnHandleInputEvent ack throttled",
1185 TRACE_EVENT_SCOPE_THREAD);
1186 if (pending_input_event_ack_) {
1187 // As two different kinds of events could cause us to postpone an ack
1188 // we send it now, if we have one pending. The Browser should never
1189 // send us the same kind of event we are delaying the ack for.
1190 Send(pending_input_event_ack_.release());
1192 pending_input_event_ack_ = response.Pass();
1193 if (compositor_)
1194 compositor_->NotifyInputThrottledUntilCommit();
1195 } else {
1196 Send(response.release());
1200 #if defined(OS_ANDROID)
1201 // Allow the IME to be shown when the focus changes as a consequence
1202 // of a processed touch end event.
1203 if (input_event->type == WebInputEvent::TouchEnd && processed)
1204 UpdateTextInputState(true, true);
1205 #endif
1207 TRACE_EVENT_SYNTHETIC_DELAY_END("blink.HandleInputEvent");
1208 handling_input_event_ = false;
1210 if (!prevent_default) {
1211 if (WebInputEvent::isKeyboardEventType(input_event->type))
1212 DidHandleKeyEvent();
1213 if (WebInputEvent::isMouseEventType(input_event->type))
1214 DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event)));
1215 if (WebInputEvent::isTouchEventType(input_event->type))
1216 DidHandleTouchEvent(*(static_cast<const WebTouchEvent*>(input_event)));
1220 void RenderWidget::OnCursorVisibilityChange(bool is_visible) {
1221 if (webwidget_)
1222 webwidget_->setCursorVisibilityState(is_visible);
1225 void RenderWidget::OnMouseCaptureLost() {
1226 if (webwidget_)
1227 webwidget_->mouseCaptureLost();
1230 void RenderWidget::OnSetFocus(bool enable) {
1231 has_focus_ = enable;
1232 if (webwidget_)
1233 webwidget_->setFocus(enable);
1236 void RenderWidget::ClearFocus() {
1237 // We may have got the focus from the browser before this gets processed, in
1238 // which case we do not want to unfocus ourself.
1239 if (!has_focus_ && webwidget_)
1240 webwidget_->setFocus(false);
1243 void RenderWidget::PaintRect(const gfx::Rect& rect,
1244 const gfx::Point& canvas_origin,
1245 skia::PlatformCanvas* canvas) {
1246 TRACE_EVENT2("renderer", "PaintRect",
1247 "width", rect.width(), "height", rect.height());
1249 canvas->save();
1251 // Bring the canvas into the coordinate system of the paint rect.
1252 canvas->translate(static_cast<SkScalar>(-canvas_origin.x()),
1253 static_cast<SkScalar>(-canvas_origin.y()));
1255 // If there is a custom background, tile it.
1256 if (!background_.empty()) {
1257 SkPaint paint;
1258 skia::RefPtr<SkShader> shader = skia::AdoptRef(
1259 SkShader::CreateBitmapShader(background_,
1260 SkShader::kRepeat_TileMode,
1261 SkShader::kRepeat_TileMode));
1262 paint.setShader(shader.get());
1264 // Use kSrc_Mode to handle background_ transparency properly.
1265 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1267 // Canvas could contain multiple update rects. Clip to given rect so that
1268 // we don't accidentally clear other update rects.
1269 canvas->save();
1270 canvas->scale(device_scale_factor_, device_scale_factor_);
1271 canvas->clipRect(gfx::RectToSkRect(rect));
1272 canvas->drawPaint(paint);
1273 canvas->restore();
1276 // First see if this rect is a plugin that can paint itself faster.
1277 TransportDIB* optimized_dib = NULL;
1278 gfx::Rect optimized_copy_rect, optimized_copy_location;
1279 float dib_scale_factor;
1280 PepperPluginInstanceImpl* optimized_instance =
1281 GetBitmapForOptimizedPluginPaint(rect, &optimized_dib,
1282 &optimized_copy_location,
1283 &optimized_copy_rect,
1284 &dib_scale_factor);
1285 if (optimized_instance) {
1286 #if defined(ENABLE_PLUGINS)
1287 // This plugin can be optimize-painted and we can just ask it to paint
1288 // itself. We don't actually need the TransportDIB in this case.
1290 // This is an optimization for PPAPI plugins that know they're on top of
1291 // the page content. If this rect is inside such a plugin, we can save some
1292 // time and avoid re-rendering the page content which we know will be
1293 // covered by the plugin later (this time can be significant, especially
1294 // for a playing movie that is invalidating a lot).
1296 // In the plugin movie case, hopefully the similar call to
1297 // GetBitmapForOptimizedPluginPaint in DoDeferredUpdate handles the
1298 // painting, because that avoids copying the plugin image to a different
1299 // paint rect. Unfortunately, if anything on the page is animating other
1300 // than the movie, it break this optimization since the union of the
1301 // invalid regions will be larger than the plugin.
1303 // This code optimizes that case, where we can still avoid painting in
1304 // WebKit and filling the background (which can be slow) and just painting
1305 // the plugin. Unlike the DoDeferredUpdate case, an extra copy is still
1306 // required.
1307 SkAutoCanvasRestore auto_restore(canvas, true);
1308 canvas->scale(device_scale_factor_, device_scale_factor_);
1309 optimized_instance->Paint(canvas, optimized_copy_location, rect);
1310 canvas->restore();
1311 #endif
1312 } else {
1313 // Normal painting case.
1314 base::TimeTicks start_time;
1315 if (!is_accelerated_compositing_active_)
1316 start_time = legacy_software_mode_stats_->StartRecording();
1318 webwidget_->paint(canvas, rect);
1320 if (!is_accelerated_compositing_active_) {
1321 base::TimeDelta paint_time =
1322 legacy_software_mode_stats_->EndRecording(start_time);
1323 int64 painted_pixel_count = rect.width() * rect.height();
1324 legacy_software_mode_stats_->AddPaint(paint_time, painted_pixel_count);
1327 // Flush to underlying bitmap. TODO(darin): is this needed?
1328 skia::GetTopDevice(*canvas)->accessBitmap(false);
1331 PaintDebugBorder(rect, canvas);
1332 canvas->restore();
1335 void RenderWidget::PaintDebugBorder(const gfx::Rect& rect,
1336 skia::PlatformCanvas* canvas) {
1337 static bool kPaintBorder =
1338 CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowPaintRects);
1339 if (!kPaintBorder)
1340 return;
1342 // Cycle through these colors to help distinguish new paint rects.
1343 const SkColor colors[] = {
1344 SkColorSetARGB(0x3F, 0xFF, 0, 0),
1345 SkColorSetARGB(0x3F, 0xFF, 0, 0xFF),
1346 SkColorSetARGB(0x3F, 0, 0, 0xFF),
1348 static int color_selector = 0;
1350 SkPaint paint;
1351 paint.setStyle(SkPaint::kStroke_Style);
1352 paint.setColor(colors[color_selector++ % arraysize(colors)]);
1353 paint.setStrokeWidth(1);
1355 SkIRect irect;
1356 irect.set(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1);
1357 canvas->drawIRect(irect, paint);
1360 void RenderWidget::AnimationCallback() {
1361 TRACE_EVENT0("renderer", "RenderWidget::AnimationCallback");
1362 if (!animation_update_pending_) {
1363 TRACE_EVENT0("renderer", "EarlyOut_NoAnimationUpdatePending");
1364 return;
1366 if (!animation_floor_time_.is_null() && IsRenderingVSynced()) {
1367 // Record when we fired (according to base::Time::Now()) relative to when
1368 // we posted the task to quantify how much the base::Time/base::TimeTicks
1369 // skew is affecting animations.
1370 base::TimeDelta animation_callback_delay = base::Time::Now() -
1371 (animation_floor_time_ - base::TimeDelta::FromMilliseconds(16));
1372 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.AnimationCallbackDelayTime",
1373 animation_callback_delay,
1374 base::TimeDelta::FromMilliseconds(0),
1375 base::TimeDelta::FromMilliseconds(30),
1376 25);
1378 DoDeferredUpdateAndSendInputAck();
1381 void RenderWidget::AnimateIfNeeded() {
1382 if (!animation_update_pending_)
1383 return;
1385 // Target 60FPS if vsync is on. Go as fast as we can if vsync is off.
1386 base::TimeDelta animationInterval = IsRenderingVSynced() ?
1387 base::TimeDelta::FromMilliseconds(16) : base::TimeDelta();
1389 base::Time now = base::Time::Now();
1391 // animation_floor_time_ is the earliest time that we should animate when
1392 // using the dead reckoning software scheduler. If we're using swapbuffers
1393 // complete callbacks to rate limit, we can ignore this floor.
1394 if (now >= animation_floor_time_ || num_swapbuffers_complete_pending_ > 0) {
1395 TRACE_EVENT0("renderer", "RenderWidget::AnimateIfNeeded")
1396 animation_floor_time_ = now + animationInterval;
1397 // Set a timer to call us back after animationInterval before
1398 // running animation callbacks so that if a callback requests another
1399 // we'll be sure to run it at the proper time.
1400 animation_timer_.Stop();
1401 animation_timer_.Start(FROM_HERE, animationInterval, this,
1402 &RenderWidget::AnimationCallback);
1403 animation_update_pending_ = false;
1404 if (is_accelerated_compositing_active_ && compositor_) {
1405 compositor_->Animate(base::TimeTicks::Now());
1406 } else {
1407 double frame_begin_time =
1408 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
1409 webwidget_->animate(frame_begin_time);
1411 return;
1413 TRACE_EVENT0("renderer", "EarlyOut_AnimatedTooRecently");
1414 if (!animation_timer_.IsRunning()) {
1415 // This code uses base::Time::Now() to calculate the floor and next fire
1416 // time because javascript's Date object uses base::Time::Now(). The
1417 // message loop uses base::TimeTicks, which on windows can have a
1418 // different granularity than base::Time.
1419 // The upshot of all this is that this function might be called before
1420 // base::Time::Now() has advanced past the animation_floor_time_. To
1421 // avoid exposing this delay to javascript, we keep posting delayed
1422 // tasks until base::Time::Now() has advanced far enough.
1423 base::TimeDelta delay = animation_floor_time_ - now;
1424 animation_timer_.Start(FROM_HERE, delay, this,
1425 &RenderWidget::AnimationCallback);
1429 bool RenderWidget::IsRenderingVSynced() {
1430 // TODO(nduca): Forcing a driver to disable vsync (e.g. in a control panel) is
1431 // not caught by this check. This will lead to artificially low frame rates
1432 // for people who force vsync off at a driver level and expect Chrome to speed
1433 // up.
1434 return !has_disable_gpu_vsync_switch_;
1437 void RenderWidget::InvalidationCallback() {
1438 TRACE_EVENT0("renderer", "RenderWidget::InvalidationCallback");
1439 invalidation_task_posted_ = false;
1440 DoDeferredUpdateAndSendInputAck();
1443 void RenderWidget::FlushPendingInputEventAck() {
1444 if (pending_input_event_ack_)
1445 Send(pending_input_event_ack_.release());
1446 total_input_handling_time_this_frame_ = base::TimeDelta();
1449 void RenderWidget::DoDeferredUpdateAndSendInputAck() {
1450 DoDeferredUpdate();
1451 FlushPendingInputEventAck();
1454 void RenderWidget::DoDeferredUpdate() {
1455 TRACE_EVENT0("renderer", "RenderWidget::DoDeferredUpdate");
1456 TRACE_EVENT_SCOPED_SAMPLING_STATE("Chrome", "Paint");
1458 if (!webwidget_)
1459 return;
1461 if (!init_complete_) {
1462 TRACE_EVENT0("renderer", "EarlyOut_InitNotComplete");
1463 return;
1465 if (update_reply_pending_) {
1466 TRACE_EVENT0("renderer", "EarlyOut_UpdateReplyPending");
1467 return;
1469 if (is_accelerated_compositing_active_ &&
1470 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) {
1471 TRACE_EVENT0("renderer", "EarlyOut_MaxSwapBuffersPending");
1472 return;
1475 // Suppress updating when we are hidden.
1476 if (is_hidden_ || size_.IsEmpty() || is_swapped_out_) {
1477 paint_aggregator_.ClearPendingUpdate();
1478 needs_repainting_on_restore_ = true;
1479 TRACE_EVENT0("renderer", "EarlyOut_NotVisible");
1480 return;
1483 // Tracking of frame rate jitter
1484 base::TimeTicks frame_begin_ticks = gfx::FrameTime::Now();
1485 InstrumentWillBeginFrame(0);
1486 AnimateIfNeeded();
1488 // Layout may generate more invalidation. It may also enable the
1489 // GPU acceleration, so make sure to run layout before we send the
1490 // GpuRenderingActivated message.
1491 webwidget_->layout();
1493 // Check for whether we need to track swap buffers. We need to do that after
1494 // layout() because it may have switched us to accelerated compositing.
1495 if (is_accelerated_compositing_active_)
1496 using_asynchronous_swapbuffers_ = SupportsAsynchronousSwapBuffers();
1498 // The following two can result in further layout and possibly
1499 // enable GPU acceleration so they need to be called before any painting
1500 // is done.
1501 UpdateTextInputType();
1502 UpdateSelectionBounds();
1504 // Suppress painting if nothing is dirty. This has to be done after updating
1505 // animations running layout as these may generate further invalidations.
1506 if (!paint_aggregator_.HasPendingUpdate()) {
1507 TRACE_EVENT0("renderer", "EarlyOut_NoPendingUpdate");
1508 InstrumentDidCancelFrame();
1509 return;
1512 if (!is_accelerated_compositing_active_ &&
1513 !is_threaded_compositing_enabled_ &&
1514 (ForceCompositingModeEnabled() ||
1515 was_accelerated_compositing_ever_active_)) {
1516 webwidget_->enterForceCompositingMode(true);
1519 if (!last_do_deferred_update_time_.is_null()) {
1520 base::TimeDelta delay = frame_begin_ticks - last_do_deferred_update_time_;
1521 if (is_accelerated_compositing_active_) {
1522 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.AccelDoDeferredUpdateDelay",
1523 delay,
1524 base::TimeDelta::FromMilliseconds(1),
1525 base::TimeDelta::FromMilliseconds(120),
1526 60);
1527 } else {
1528 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.SoftwareDoDeferredUpdateDelay",
1529 delay,
1530 base::TimeDelta::FromMilliseconds(1),
1531 base::TimeDelta::FromMilliseconds(120),
1532 60);
1535 // Calculate filtered time per frame:
1536 float frame_time_elapsed = static_cast<float>(delay.InSecondsF());
1537 filtered_time_per_frame_ =
1538 0.9f * filtered_time_per_frame_ + 0.1f * frame_time_elapsed;
1540 last_do_deferred_update_time_ = frame_begin_ticks;
1542 if (!is_accelerated_compositing_active_) {
1543 legacy_software_mode_stats_->IncrementFrameCount(1, true);
1544 cc::BenchmarkInstrumentation::IssueMainThreadRenderingStatsEvent(
1545 legacy_software_mode_stats_->main_thread_rendering_stats());
1546 legacy_software_mode_stats_->AccumulateAndClearMainThreadStats();
1549 // OK, save the pending update to a local since painting may cause more
1550 // invalidation. Some WebCore rendering objects only layout when painted.
1551 PaintAggregator::PendingUpdate update;
1552 paint_aggregator_.PopPendingUpdate(&update);
1554 gfx::Rect scroll_damage = update.GetScrollDamage();
1555 gfx::Rect bounds = gfx::UnionRects(update.GetPaintBounds(), scroll_damage);
1557 // A plugin may be able to do an optimized paint. First check this, in which
1558 // case we can skip all of the bitmap generation and regular paint code.
1559 // This optimization allows PPAPI plugins that declare themselves on top of
1560 // the page (like a traditional windowed plugin) to be able to animate (think
1561 // movie playing) without repeatedly re-painting the page underneath, or
1562 // copying the plugin backing store (since we can send the plugin's backing
1563 // store directly to the browser).
1565 // This optimization only works when the entire invalid region is contained
1566 // within the plugin. There is a related optimization in PaintRect for the
1567 // case where there may be multiple invalid regions.
1568 TransportDIB* dib = NULL;
1569 gfx::Rect optimized_copy_rect, optimized_copy_location;
1570 float dib_scale_factor = 1;
1571 DCHECK(!pending_update_params_.get());
1572 pending_update_params_.reset(new ViewHostMsg_UpdateRect_Params);
1573 pending_update_params_->scroll_delta = update.scroll_delta;
1574 pending_update_params_->scroll_rect = update.scroll_rect;
1575 pending_update_params_->view_size = size_;
1576 pending_update_params_->plugin_window_moves.swap(plugin_window_moves_);
1577 pending_update_params_->flags = next_paint_flags_;
1578 pending_update_params_->scroll_offset = GetScrollOffset();
1579 pending_update_params_->needs_ack = true;
1580 pending_update_params_->scale_factor = device_scale_factor_;
1581 next_paint_flags_ = 0;
1582 need_update_rect_for_auto_resize_ = false;
1584 if (!is_accelerated_compositing_active_)
1585 pending_update_params_->latency_info.swap(latency_info_);
1587 latency_info_.clear();
1589 if (update.scroll_rect.IsEmpty() &&
1590 !is_accelerated_compositing_active_ &&
1591 GetBitmapForOptimizedPluginPaint(bounds, &dib, &optimized_copy_location,
1592 &optimized_copy_rect,
1593 &dib_scale_factor)) {
1594 // Only update the part of the plugin that actually changed.
1595 optimized_copy_rect.Intersect(bounds);
1596 pending_update_params_->bitmap = dib->id();
1597 pending_update_params_->bitmap_rect = optimized_copy_location;
1598 pending_update_params_->copy_rects.push_back(optimized_copy_rect);
1599 pending_update_params_->scale_factor = dib_scale_factor;
1600 } else if (!is_accelerated_compositing_active_) {
1601 // Compute a buffer for painting and cache it.
1603 bool fractional_scale = device_scale_factor_ -
1604 static_cast<int>(device_scale_factor_) != 0;
1605 if (fractional_scale) {
1606 // Damage might not be DIP aligned. Inflate damage to compensate.
1607 bounds.Inset(-1, -1);
1608 bounds.Intersect(gfx::Rect(size_));
1611 gfx::Rect pixel_bounds = gfx::ToEnclosingRect(
1612 gfx::ScaleRect(bounds, device_scale_factor_));
1614 scoped_ptr<skia::PlatformCanvas> canvas(
1615 RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_,
1616 pixel_bounds));
1617 if (!canvas) {
1618 NOTREACHED();
1619 return;
1622 // We may get back a smaller canvas than we asked for.
1623 // TODO(darin): This seems like it could cause painting problems!
1624 DCHECK_EQ(pixel_bounds.width(), canvas->getDevice()->width());
1625 DCHECK_EQ(pixel_bounds.height(), canvas->getDevice()->height());
1626 pixel_bounds.set_width(canvas->getDevice()->width());
1627 pixel_bounds.set_height(canvas->getDevice()->height());
1628 bounds.set_width(pixel_bounds.width() / device_scale_factor_);
1629 bounds.set_height(pixel_bounds.height() / device_scale_factor_);
1631 HISTOGRAM_COUNTS_100("MPArch.RW_PaintRectCount", update.paint_rects.size());
1633 pending_update_params_->bitmap = current_paint_buf_->id();
1634 pending_update_params_->bitmap_rect = bounds;
1636 std::vector<gfx::Rect>& copy_rects = pending_update_params_->copy_rects;
1637 // The scroll damage is just another rectangle to paint and copy.
1638 copy_rects.swap(update.paint_rects);
1639 if (!scroll_damage.IsEmpty())
1640 copy_rects.push_back(scroll_damage);
1642 for (size_t i = 0; i < copy_rects.size(); ++i) {
1643 gfx::Rect rect = copy_rects[i];
1644 if (fractional_scale) {
1645 // Damage might not be DPI aligned. Inflate rect to compensate.
1646 rect.Inset(-1, -1);
1648 PaintRect(rect, pixel_bounds.origin(), canvas.get());
1651 // Software FPS tick for performance tests. The accelerated path traces the
1652 // frame events in didCommitAndDrawCompositorFrame. See throughput_tests.cc.
1653 // NOTE: Tests may break if this event is renamed or moved.
1654 UNSHIPPED_TRACE_EVENT_INSTANT0("test_fps", "TestFrameTickSW",
1655 TRACE_EVENT_SCOPE_THREAD);
1656 } else { // Accelerated compositing path
1657 // Begin painting.
1658 // If painting is done via the gpu process then we don't set any damage
1659 // rects to save the browser process from doing unecessary work.
1660 pending_update_params_->bitmap_rect = bounds;
1661 pending_update_params_->scroll_rect = gfx::Rect();
1662 // We don't need an ack, because we're not sharing a DIB with the browser.
1663 // If it needs to (e.g. composited UI), the GPU process does its own ACK
1664 // with the browser for the GPU surface.
1665 pending_update_params_->needs_ack = false;
1666 Composite(frame_begin_ticks);
1669 // If we're holding a pending input event ACK, send the ACK before sending the
1670 // UpdateReply message so we can receive another input event before the
1671 // UpdateRect_ACK on platforms where the UpdateRect_ACK is sent from within
1672 // the UpdateRect IPC message handler.
1673 FlushPendingInputEventAck();
1675 // If Composite() called SwapBuffers, pending_update_params_ will be reset (in
1676 // OnSwapBuffersPosted), meaning a message has been added to the
1677 // updates_pending_swap_ queue, that will be sent later. Otherwise, we send
1678 // the message now.
1679 if (pending_update_params_) {
1680 // sending an ack to browser process that the paint is complete...
1681 update_reply_pending_ = pending_update_params_->needs_ack;
1682 Send(new ViewHostMsg_UpdateRect(routing_id_, *pending_update_params_));
1683 pending_update_params_.reset();
1686 // If we're software rendering then we're done initiating the paint.
1687 if (!is_accelerated_compositing_active_)
1688 DidInitiatePaint();
1691 void RenderWidget::Composite(base::TimeTicks frame_begin_time) {
1692 DCHECK(is_accelerated_compositing_active_);
1693 if (compositor_) // TODO(jamesr): Figure out how this can be null.
1694 compositor_->Composite(frame_begin_time);
1697 ///////////////////////////////////////////////////////////////////////////////
1698 // WebWidgetClient
1700 void RenderWidget::didInvalidateRect(const WebRect& rect) {
1701 // The invalidated rect might be outside the bounds of the view.
1702 gfx::Rect view_rect(size_);
1703 gfx::Rect damaged_rect = gfx::IntersectRects(view_rect, rect);
1704 if (damaged_rect.IsEmpty())
1705 return;
1707 paint_aggregator_.InvalidateRect(damaged_rect);
1709 // We may not need to schedule another call to DoDeferredUpdate.
1710 if (invalidation_task_posted_)
1711 return;
1712 if (!paint_aggregator_.HasPendingUpdate())
1713 return;
1714 if (update_reply_pending_ ||
1715 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending)
1716 return;
1718 // When GPU rendering, combine pending animations and invalidations into
1719 // a single update.
1720 if (is_accelerated_compositing_active_ &&
1721 animation_update_pending_ &&
1722 animation_timer_.IsRunning())
1723 return;
1725 // Perform updating asynchronously. This serves two purposes:
1726 // 1) Ensures that we call WebView::Paint without a bunch of other junk
1727 // on the call stack.
1728 // 2) Allows us to collect more damage rects before painting to help coalesce
1729 // the work that we will need to do.
1730 invalidation_task_posted_ = true;
1731 base::MessageLoop::current()->PostTask(
1732 FROM_HERE, base::Bind(&RenderWidget::InvalidationCallback, this));
1735 void RenderWidget::didScrollRect(int dx, int dy,
1736 const WebRect& clip_rect) {
1737 // Drop scrolls on the floor when we are in compositing mode.
1738 // TODO(nduca): stop WebViewImpl from sending scrolls in the first place.
1739 if (is_accelerated_compositing_active_)
1740 return;
1742 // The scrolled rect might be outside the bounds of the view.
1743 gfx::Rect view_rect(size_);
1744 gfx::Rect damaged_rect = gfx::IntersectRects(view_rect, clip_rect);
1745 if (damaged_rect.IsEmpty())
1746 return;
1748 paint_aggregator_.ScrollRect(gfx::Vector2d(dx, dy), damaged_rect);
1750 // We may not need to schedule another call to DoDeferredUpdate.
1751 if (invalidation_task_posted_)
1752 return;
1753 if (!paint_aggregator_.HasPendingUpdate())
1754 return;
1755 if (update_reply_pending_ ||
1756 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending)
1757 return;
1759 // When GPU rendering, combine pending animations and invalidations into
1760 // a single update.
1761 if (is_accelerated_compositing_active_ &&
1762 animation_update_pending_ &&
1763 animation_timer_.IsRunning())
1764 return;
1766 // Perform updating asynchronously. This serves two purposes:
1767 // 1) Ensures that we call WebView::Paint without a bunch of other junk
1768 // on the call stack.
1769 // 2) Allows us to collect more damage rects before painting to help coalesce
1770 // the work that we will need to do.
1771 invalidation_task_posted_ = true;
1772 base::MessageLoop::current()->PostTask(
1773 FROM_HERE, base::Bind(&RenderWidget::InvalidationCallback, this));
1776 void RenderWidget::didAutoResize(const WebSize& new_size) {
1777 if (size_.width() != new_size.width || size_.height() != new_size.height) {
1778 size_ = new_size;
1780 // If we don't clear PaintAggregator after changing autoResize state, then
1781 // we might end up in a situation where bitmap_rect is larger than the
1782 // view_size. By clearing PaintAggregator, we ensure that we don't end up
1783 // with invalid damage rects.
1784 paint_aggregator_.ClearPendingUpdate();
1786 if (resizing_mode_selector_->is_synchronous_mode()) {
1787 WebRect new_pos(rootWindowRect().x,
1788 rootWindowRect().y,
1789 new_size.width,
1790 new_size.height);
1791 view_screen_rect_ = new_pos;
1792 window_screen_rect_ = new_pos;
1795 AutoResizeCompositor();
1797 if (!resizing_mode_selector_->is_synchronous_mode())
1798 need_update_rect_for_auto_resize_ = true;
1802 void RenderWidget::AutoResizeCompositor() {
1803 physical_backing_size_ = gfx::ToCeiledSize(gfx::ScaleSize(size_,
1804 device_scale_factor_));
1805 if (compositor_)
1806 compositor_->setViewportSize(size_, physical_backing_size_);
1809 void RenderWidget::didActivateCompositor(int input_handler_identifier) {
1810 TRACE_EVENT0("gpu", "RenderWidget::didActivateCompositor");
1812 #if !defined(OS_MACOSX)
1813 if (!is_accelerated_compositing_active_) {
1814 // When not in accelerated compositing mode, in certain cases (e.g. waiting
1815 // for a resize or if no backing store) the RenderWidgetHost is blocking the
1816 // browser's UI thread for some time, waiting for an UpdateRect. If we are
1817 // going to switch to accelerated compositing, the GPU process may need
1818 // round-trips to the browser's UI thread before finishing the frame,
1819 // causing deadlocks if we delay the UpdateRect until we receive the
1820 // OnSwapBuffersComplete. So send a dummy message that will unblock the
1821 // browser's UI thread. This is not necessary on Mac, because SwapBuffers
1822 // now unblocks GetBackingStore on Mac.
1823 Send(new ViewHostMsg_UpdateIsDelayed(routing_id_));
1825 #endif
1827 is_accelerated_compositing_active_ = true;
1828 Send(new ViewHostMsg_DidActivateAcceleratedCompositing(
1829 routing_id_, is_accelerated_compositing_active_));
1831 if (!was_accelerated_compositing_ever_active_) {
1832 was_accelerated_compositing_ever_active_ = true;
1833 webwidget_->enterForceCompositingMode(true);
1837 void RenderWidget::didDeactivateCompositor() {
1838 TRACE_EVENT0("gpu", "RenderWidget::didDeactivateCompositor");
1840 is_accelerated_compositing_active_ = false;
1841 Send(new ViewHostMsg_DidActivateAcceleratedCompositing(
1842 routing_id_, is_accelerated_compositing_active_));
1844 if (using_asynchronous_swapbuffers_)
1845 using_asynchronous_swapbuffers_ = false;
1847 // In single-threaded mode, we exit force compositing mode and re-enter in
1848 // DoDeferredUpdate() if appropriate. In threaded compositing mode,
1849 // DoDeferredUpdate() is bypassed and WebKit is responsible for exiting and
1850 // entering force compositing mode at the appropriate times.
1851 if (!is_threaded_compositing_enabled_)
1852 webwidget_->enterForceCompositingMode(false);
1855 void RenderWidget::initializeLayerTreeView() {
1856 compositor_ = RenderWidgetCompositor::Create(
1857 this, is_threaded_compositing_enabled_);
1858 if (!compositor_)
1859 return;
1861 compositor_->setViewportSize(size_, physical_backing_size_);
1862 if (init_complete_)
1863 compositor_->setSurfaceReady();
1866 blink::WebLayerTreeView* RenderWidget::layerTreeView() {
1867 return compositor_.get();
1870 void RenderWidget::suppressCompositorScheduling(bool enable) {
1871 if (compositor_)
1872 compositor_->SetSuppressScheduleComposite(enable);
1875 void RenderWidget::willBeginCompositorFrame() {
1876 TRACE_EVENT0("gpu", "RenderWidget::willBeginCompositorFrame");
1878 DCHECK(RenderThreadImpl::current()->compositor_message_loop_proxy().get());
1880 // The following two can result in further layout and possibly
1881 // enable GPU acceleration so they need to be called before any painting
1882 // is done.
1883 UpdateTextInputType();
1884 #if defined(OS_ANDROID)
1885 UpdateTextInputState(false, true);
1886 #endif
1887 UpdateSelectionBounds();
1890 void RenderWidget::didBecomeReadyForAdditionalInput() {
1891 TRACE_EVENT0("renderer", "RenderWidget::didBecomeReadyForAdditionalInput");
1892 FlushPendingInputEventAck();
1895 void RenderWidget::DidCommitCompositorFrame() {
1898 void RenderWidget::didCommitAndDrawCompositorFrame() {
1899 TRACE_EVENT0("gpu", "RenderWidget::didCommitAndDrawCompositorFrame");
1900 // Accelerated FPS tick for performance tests. See throughput_tests.cc.
1901 // NOTE: Tests may break if this event is renamed or moved.
1902 UNSHIPPED_TRACE_EVENT_INSTANT0("test_fps", "TestFrameTickGPU",
1903 TRACE_EVENT_SCOPE_THREAD);
1904 // Notify subclasses that we initiated the paint operation.
1905 DidInitiatePaint();
1908 void RenderWidget::didCompleteSwapBuffers() {
1909 TRACE_EVENT0("renderer", "RenderWidget::didCompleteSwapBuffers");
1911 // Notify subclasses threaded composited rendering was flushed to the screen.
1912 DidFlushPaint();
1914 if (update_reply_pending_)
1915 return;
1917 if (!next_paint_flags_ &&
1918 !need_update_rect_for_auto_resize_ &&
1919 !plugin_window_moves_.size()) {
1920 return;
1923 ViewHostMsg_UpdateRect_Params params;
1924 params.view_size = size_;
1925 params.plugin_window_moves.swap(plugin_window_moves_);
1926 params.flags = next_paint_flags_;
1927 params.scroll_offset = GetScrollOffset();
1928 params.needs_ack = false;
1929 params.scale_factor = device_scale_factor_;
1931 Send(new ViewHostMsg_UpdateRect(routing_id_, params));
1932 next_paint_flags_ = 0;
1933 need_update_rect_for_auto_resize_ = false;
1936 void RenderWidget::scheduleComposite() {
1937 if (RenderThreadImpl::current()->compositor_message_loop_proxy().get() &&
1938 compositor_) {
1939 compositor_->setNeedsAnimate();
1940 } else {
1941 // TODO(nduca): replace with something a little less hacky. The reason this
1942 // hack is still used is because the Invalidate-DoDeferredUpdate loop
1943 // contains a lot of host-renderer synchronization logic that is still
1944 // important for the accelerated compositing case. The option of simply
1945 // duplicating all that code is less desirable than "faking out" the
1946 // invalidation path using a magical damage rect.
1947 didInvalidateRect(WebRect(0, 0, 1, 1));
1951 void RenderWidget::scheduleAnimation() {
1952 if (animation_update_pending_)
1953 return;
1955 TRACE_EVENT0("gpu", "RenderWidget::scheduleAnimation");
1956 animation_update_pending_ = true;
1957 if (!animation_timer_.IsRunning()) {
1958 animation_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(0), this,
1959 &RenderWidget::AnimationCallback);
1963 void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) {
1964 // TODO(darin): Eliminate this temporary.
1965 WebCursor cursor;
1966 InitializeCursorFromWebKitCursorInfo(&cursor, cursor_info);
1967 // Only send a SetCursor message if we need to make a change.
1968 if (!current_cursor_.IsEqual(cursor)) {
1969 current_cursor_ = cursor;
1970 Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
1974 // We are supposed to get a single call to Show for a newly created RenderWidget
1975 // that was created via RenderWidget::CreateWebView. So, we wait until this
1976 // point to dispatch the ShowWidget message.
1978 // This method provides us with the information about how to display the newly
1979 // created RenderWidget (i.e., as a blocked popup or as a new tab).
1981 void RenderWidget::show(WebNavigationPolicy) {
1982 DCHECK(!did_show_) << "received extraneous Show call";
1983 DCHECK(routing_id_ != MSG_ROUTING_NONE);
1984 DCHECK(opener_id_ != MSG_ROUTING_NONE);
1986 if (did_show_)
1987 return;
1989 did_show_ = true;
1990 // NOTE: initial_pos_ may still have its default values at this point, but
1991 // that's okay. It'll be ignored if as_popup is false, or the browser
1992 // process will impose a default position otherwise.
1993 Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_pos_));
1994 SetPendingWindowRect(initial_pos_);
1997 void RenderWidget::didFocus() {
2000 void RenderWidget::didBlur() {
2003 void RenderWidget::DoDeferredClose() {
2004 Send(new ViewHostMsg_Close(routing_id_));
2007 void RenderWidget::closeWidgetSoon() {
2008 if (is_swapped_out_) {
2009 // This widget is currently swapped out, and the active widget is in a
2010 // different process. Have the browser route the close request to the
2011 // active widget instead, so that the correct unload handlers are run.
2012 Send(new ViewHostMsg_RouteCloseEvent(routing_id_));
2013 return;
2016 // If a page calls window.close() twice, we'll end up here twice, but that's
2017 // OK. It is safe to send multiple Close messages.
2019 // Ask the RenderWidgetHost to initiate close. We could be called from deep
2020 // in Javascript. If we ask the RendwerWidgetHost to close now, the window
2021 // could be closed before the JS finishes executing. So instead, post a
2022 // message back to the message loop, which won't run until the JS is
2023 // complete, and then the Close message can be sent.
2024 base::MessageLoop::current()->PostTask(
2025 FROM_HERE, base::Bind(&RenderWidget::DoDeferredClose, this));
2028 void RenderWidget::QueueSyntheticGesture(
2029 scoped_ptr<SyntheticGestureParams> gesture_params,
2030 const SyntheticGestureCompletionCallback& callback) {
2031 DCHECK(!callback.is_null());
2033 pending_synthetic_gesture_callbacks_.push(callback);
2035 SyntheticGesturePacket gesture_packet;
2036 gesture_packet.set_gesture_params(gesture_params.Pass());
2038 Send(new InputHostMsg_QueueSyntheticGesture(routing_id_, gesture_packet));
2041 void RenderWidget::Close() {
2042 if (webwidget_) {
2043 webwidget_->willCloseLayerTreeView();
2044 compositor_.reset();
2045 webwidget_->close();
2046 webwidget_ = NULL;
2050 WebRect RenderWidget::windowRect() {
2051 if (pending_window_rect_count_)
2052 return pending_window_rect_;
2054 return view_screen_rect_;
2057 void RenderWidget::setToolTipText(const blink::WebString& text,
2058 WebTextDirection hint) {
2059 Send(new ViewHostMsg_SetTooltipText(routing_id_, text, hint));
2062 void RenderWidget::setWindowRect(const WebRect& rect) {
2063 WebRect pos = rect;
2064 if (popup_origin_scale_for_emulation_) {
2065 float scale = popup_origin_scale_for_emulation_;
2066 pos.x = popup_screen_origin_for_emulation_.x() +
2067 (pos.x - popup_view_origin_for_emulation_.x()) * scale;
2068 pos.y = popup_screen_origin_for_emulation_.y() +
2069 (pos.y - popup_view_origin_for_emulation_.y()) * scale;
2072 if (!resizing_mode_selector_->is_synchronous_mode()) {
2073 if (did_show_) {
2074 Send(new ViewHostMsg_RequestMove(routing_id_, pos));
2075 SetPendingWindowRect(pos);
2076 } else {
2077 initial_pos_ = pos;
2079 } else {
2080 ResizeSynchronously(pos);
2084 void RenderWidget::SetPendingWindowRect(const WebRect& rect) {
2085 pending_window_rect_ = rect;
2086 pending_window_rect_count_++;
2089 WebRect RenderWidget::rootWindowRect() {
2090 if (pending_window_rect_count_) {
2091 // NOTE(mbelshe): If there is a pending_window_rect_, then getting
2092 // the RootWindowRect is probably going to return wrong results since the
2093 // browser may not have processed the Move yet. There isn't really anything
2094 // good to do in this case, and it shouldn't happen - since this size is
2095 // only really needed for windowToScreen, which is only used for Popups.
2096 return pending_window_rect_;
2099 return window_screen_rect_;
2102 WebRect RenderWidget::windowResizerRect() {
2103 return resizer_rect_;
2106 void RenderWidget::OnSetInputMethodActive(bool is_active) {
2107 // To prevent this renderer process from sending unnecessary IPC messages to
2108 // a browser process, we permit the renderer process to send IPC messages
2109 // only during the input method attached to the browser process is active.
2110 input_method_is_active_ = is_active;
2113 void RenderWidget::OnCandidateWindowShown() {
2114 webwidget_->didShowCandidateWindow();
2117 void RenderWidget::OnCandidateWindowUpdated() {
2118 webwidget_->didUpdateCandidateWindow();
2121 void RenderWidget::OnCandidateWindowHidden() {
2122 webwidget_->didHideCandidateWindow();
2125 void RenderWidget::OnImeSetComposition(
2126 const base::string16& text,
2127 const std::vector<WebCompositionUnderline>& underlines,
2128 int selection_start, int selection_end) {
2129 if (!ShouldHandleImeEvent())
2130 return;
2131 ImeEventGuard guard(this);
2132 if (!webwidget_->setComposition(
2133 text, WebVector<WebCompositionUnderline>(underlines),
2134 selection_start, selection_end)) {
2135 // If we failed to set the composition text, then we need to let the browser
2136 // process to cancel the input method's ongoing composition session, to make
2137 // sure we are in a consistent state.
2138 Send(new ViewHostMsg_ImeCancelComposition(routing_id()));
2140 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
2141 UpdateCompositionInfo(true);
2142 #endif
2145 void RenderWidget::OnImeConfirmComposition(const base::string16& text,
2146 const gfx::Range& replacement_range,
2147 bool keep_selection) {
2148 if (!ShouldHandleImeEvent())
2149 return;
2150 ImeEventGuard guard(this);
2151 handling_input_event_ = true;
2152 if (text.length())
2153 webwidget_->confirmComposition(text);
2154 else if (keep_selection)
2155 webwidget_->confirmComposition(WebWidget::KeepSelection);
2156 else
2157 webwidget_->confirmComposition(WebWidget::DoNotKeepSelection);
2158 handling_input_event_ = false;
2159 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
2160 UpdateCompositionInfo(true);
2161 #endif
2164 // This message causes the renderer to render an image of the
2165 // desired_size, regardless of whether the tab is hidden or not.
2166 void RenderWidget::OnPaintAtSize(const TransportDIB::Handle& dib_handle,
2167 int tag,
2168 const gfx::Size& page_size,
2169 const gfx::Size& desired_size) {
2170 if (!webwidget_ || !TransportDIB::is_valid_handle(dib_handle)) {
2171 if (TransportDIB::is_valid_handle(dib_handle)) {
2172 // Close our unused handle.
2173 #if defined(OS_WIN)
2174 ::CloseHandle(dib_handle);
2175 #elif defined(OS_MACOSX)
2176 base::SharedMemory::CloseHandle(dib_handle);
2177 #endif
2179 return;
2182 if (page_size.IsEmpty() || desired_size.IsEmpty()) {
2183 // If one of these is empty, then we just return the dib we were
2184 // given, to avoid leaking it.
2185 Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, desired_size));
2186 return;
2189 // Map the given DIB ID into this process, and unmap it at the end
2190 // of this function.
2191 scoped_ptr<TransportDIB> paint_at_size_buffer(
2192 TransportDIB::CreateWithHandle(dib_handle));
2194 gfx::Size page_size_in_pixel = gfx::ToFlooredSize(
2195 gfx::ScaleSize(page_size, device_scale_factor_));
2196 gfx::Size desired_size_in_pixel = gfx::ToFlooredSize(
2197 gfx::ScaleSize(desired_size, device_scale_factor_));
2198 gfx::Size canvas_size = page_size_in_pixel;
2199 float x_scale = static_cast<float>(desired_size_in_pixel.width()) /
2200 static_cast<float>(canvas_size.width());
2201 float y_scale = static_cast<float>(desired_size_in_pixel.height()) /
2202 static_cast<float>(canvas_size.height());
2204 gfx::Rect orig_bounds(canvas_size);
2205 canvas_size.set_width(static_cast<int>(canvas_size.width() * x_scale));
2206 canvas_size.set_height(static_cast<int>(canvas_size.height() * y_scale));
2207 gfx::Rect bounds(canvas_size);
2209 scoped_ptr<skia::PlatformCanvas> canvas(
2210 paint_at_size_buffer->GetPlatformCanvas(canvas_size.width(),
2211 canvas_size.height()));
2212 if (!canvas) {
2213 NOTREACHED();
2214 return;
2217 // Reset bounds to what we actually received, but they should be the
2218 // same.
2219 DCHECK_EQ(bounds.width(), canvas->getDevice()->width());
2220 DCHECK_EQ(bounds.height(), canvas->getDevice()->height());
2221 bounds.set_width(canvas->getDevice()->width());
2222 bounds.set_height(canvas->getDevice()->height());
2224 canvas->save();
2225 // Add the scale factor to the canvas, so that we'll get the desired size.
2226 canvas->scale(SkFloatToScalar(x_scale), SkFloatToScalar(y_scale));
2228 // Have to make sure we're laid out at the right size before
2229 // rendering.
2230 gfx::Size old_size = webwidget_->size();
2231 webwidget_->resize(page_size);
2232 webwidget_->layout();
2234 // Paint the entire thing (using original bounds, not scaled bounds).
2235 PaintRect(orig_bounds, orig_bounds.origin(), canvas.get());
2236 canvas->restore();
2238 // Return the widget to its previous size.
2239 webwidget_->resize(old_size);
2241 Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, bounds.size()));
2244 void RenderWidget::OnSnapshot(const gfx::Rect& src_subrect) {
2245 SkBitmap snapshot;
2247 if (OnSnapshotHelper(src_subrect, &snapshot)) {
2248 Send(new ViewHostMsg_Snapshot(routing_id(), true, snapshot));
2249 } else {
2250 Send(new ViewHostMsg_Snapshot(routing_id(), false, SkBitmap()));
2254 bool RenderWidget::OnSnapshotHelper(const gfx::Rect& src_subrect,
2255 SkBitmap* snapshot) {
2256 base::TimeTicks beginning_time = base::TimeTicks::Now();
2258 if (!webwidget_ || src_subrect.IsEmpty())
2259 return false;
2261 gfx::Rect viewport_size = gfx::IntersectRects(
2262 src_subrect, gfx::Rect(physical_backing_size_));
2264 skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(
2265 skia::CreatePlatformCanvas(viewport_size.width(),
2266 viewport_size.height(),
2267 true,
2268 NULL,
2269 skia::RETURN_NULL_ON_FAILURE));
2270 if (!canvas)
2271 return false;
2273 canvas->save();
2274 webwidget_->layout();
2276 PaintRect(viewport_size, viewport_size.origin(), canvas.get());
2277 canvas->restore();
2279 const SkBitmap& bitmap = skia::GetTopDevice(*canvas)->accessBitmap(false);
2280 if (!bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config))
2281 return false;
2283 UMA_HISTOGRAM_TIMES("Renderer4.Snapshot",
2284 base::TimeTicks::Now() - beginning_time);
2285 return true;
2288 void RenderWidget::OnRepaint(gfx::Size size_to_paint) {
2289 // During shutdown we can just ignore this message.
2290 if (!webwidget_)
2291 return;
2293 // Even if the browser provides an empty damage rect, it's still expecting to
2294 // receive a repaint ack so just damage the entire widget bounds.
2295 if (size_to_paint.IsEmpty()) {
2296 size_to_paint = size_;
2299 set_next_paint_is_repaint_ack();
2300 if (is_accelerated_compositing_active_ && compositor_) {
2301 compositor_->SetNeedsRedrawRect(gfx::Rect(size_to_paint));
2302 } else {
2303 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height());
2304 didInvalidateRect(repaint_rect);
2308 void RenderWidget::OnSyntheticGestureCompleted() {
2309 DCHECK(!pending_synthetic_gesture_callbacks_.empty());
2311 pending_synthetic_gesture_callbacks_.front().Run();
2312 pending_synthetic_gesture_callbacks_.pop();
2315 void RenderWidget::OnSetTextDirection(WebTextDirection direction) {
2316 if (!webwidget_)
2317 return;
2318 webwidget_->setTextDirection(direction);
2321 void RenderWidget::OnUpdateScreenRects(const gfx::Rect& view_screen_rect,
2322 const gfx::Rect& window_screen_rect) {
2323 if (screen_metrics_emulator_) {
2324 screen_metrics_emulator_->OnUpdateScreenRectsMessage(
2325 view_screen_rect, window_screen_rect);
2326 } else {
2327 view_screen_rect_ = view_screen_rect;
2328 window_screen_rect_ = window_screen_rect;
2330 Send(new ViewHostMsg_UpdateScreenRects_ACK(routing_id()));
2333 #if defined(OS_ANDROID)
2334 void RenderWidget::OnShowImeIfNeeded() {
2335 UpdateTextInputState(true, true);
2338 void RenderWidget::IncrementOutstandingImeEventAcks() {
2339 ++outstanding_ime_acks_;
2342 void RenderWidget::OnImeEventAck() {
2343 --outstanding_ime_acks_;
2344 DCHECK(outstanding_ime_acks_ >= 0);
2346 #endif
2348 bool RenderWidget::ShouldHandleImeEvent() {
2349 #if defined(OS_ANDROID)
2350 return !!webwidget_ && outstanding_ime_acks_ == 0;
2351 #else
2352 return !!webwidget_;
2353 #endif
2356 void RenderWidget::SetDeviceScaleFactor(float device_scale_factor) {
2357 if (device_scale_factor_ == device_scale_factor)
2358 return;
2360 device_scale_factor_ = device_scale_factor;
2362 if (!is_accelerated_compositing_active_) {
2363 didInvalidateRect(gfx::Rect(size_.width(), size_.height()));
2364 } else {
2365 scheduleComposite();
2369 PepperPluginInstanceImpl* RenderWidget::GetBitmapForOptimizedPluginPaint(
2370 const gfx::Rect& paint_bounds,
2371 TransportDIB** dib,
2372 gfx::Rect* location,
2373 gfx::Rect* clip,
2374 float* scale_factor) {
2375 // Bare RenderWidgets don't support optimized plugin painting.
2376 return NULL;
2379 gfx::Vector2d RenderWidget::GetScrollOffset() {
2380 // Bare RenderWidgets don't support scroll offset.
2381 return gfx::Vector2d();
2384 void RenderWidget::SetHidden(bool hidden) {
2385 if (is_hidden_ == hidden)
2386 return;
2388 // The status has changed. Tell the RenderThread about it.
2389 is_hidden_ = hidden;
2390 if (is_hidden_)
2391 RenderThreadImpl::current()->WidgetHidden();
2392 else
2393 RenderThreadImpl::current()->WidgetRestored();
2396 void RenderWidget::WillToggleFullscreen() {
2397 if (!webwidget_)
2398 return;
2400 if (is_fullscreen_) {
2401 webwidget_->willExitFullScreen();
2402 } else {
2403 webwidget_->willEnterFullScreen();
2407 void RenderWidget::DidToggleFullscreen() {
2408 if (!webwidget_)
2409 return;
2411 if (is_fullscreen_) {
2412 webwidget_->didEnterFullScreen();
2413 } else {
2414 webwidget_->didExitFullScreen();
2418 void RenderWidget::SetBackground(const SkBitmap& background) {
2419 background_ = background;
2421 // Generate a full repaint.
2422 didInvalidateRect(gfx::Rect(size_.width(), size_.height()));
2425 bool RenderWidget::next_paint_is_resize_ack() const {
2426 return ViewHostMsg_UpdateRect_Flags::is_resize_ack(next_paint_flags_);
2429 bool RenderWidget::next_paint_is_restore_ack() const {
2430 return ViewHostMsg_UpdateRect_Flags::is_restore_ack(next_paint_flags_);
2433 void RenderWidget::set_next_paint_is_resize_ack() {
2434 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK;
2437 void RenderWidget::set_next_paint_is_restore_ack() {
2438 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK;
2441 void RenderWidget::set_next_paint_is_repaint_ack() {
2442 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK;
2445 static bool IsDateTimeInput(ui::TextInputType type) {
2446 return type == ui::TEXT_INPUT_TYPE_DATE ||
2447 type == ui::TEXT_INPUT_TYPE_DATE_TIME ||
2448 type == ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL ||
2449 type == ui::TEXT_INPUT_TYPE_MONTH ||
2450 type == ui::TEXT_INPUT_TYPE_TIME ||
2451 type == ui::TEXT_INPUT_TYPE_WEEK;
2455 void RenderWidget::StartHandlingImeEvent() {
2456 DCHECK(!handling_ime_event_);
2457 handling_ime_event_ = true;
2460 void RenderWidget::FinishHandlingImeEvent() {
2461 DCHECK(handling_ime_event_);
2462 handling_ime_event_ = false;
2463 // While handling an ime event, text input state and selection bounds updates
2464 // are ignored. These must explicitly be updated once finished handling the
2465 // ime event.
2466 UpdateSelectionBounds();
2467 #if defined(OS_ANDROID)
2468 UpdateTextInputState(false, false);
2469 #endif
2472 void RenderWidget::UpdateTextInputType() {
2473 // On Windows, not only an IME but also an on-screen keyboard relies on the
2474 // latest TextInputType to optimize its layout and functionality. Thus
2475 // |input_method_is_active_| is no longer an appropriate condition to suppress
2476 // TextInputTypeChanged IPC on Windows.
2477 // TODO(yukawa, yoichio): Consider to stop checking |input_method_is_active_|
2478 // on other platforms as well as Windows if the overhead is acceptable.
2479 #if !defined(OS_WIN)
2480 if (!input_method_is_active_)
2481 return;
2482 #endif
2484 ui::TextInputType new_type = GetTextInputType();
2485 if (IsDateTimeInput(new_type))
2486 return; // Not considered as a text input field in WebKit/Chromium.
2488 bool new_can_compose_inline = CanComposeInline();
2490 blink::WebTextInputInfo new_info;
2491 if (webwidget_)
2492 new_info = webwidget_->textInputInfo();
2493 const ui::TextInputMode new_mode = ConvertInputMode(new_info.inputMode);
2495 if (text_input_type_ != new_type
2496 || can_compose_inline_ != new_can_compose_inline
2497 || text_input_mode_ != new_mode) {
2498 Send(new ViewHostMsg_TextInputTypeChanged(routing_id(),
2499 new_type,
2500 new_mode,
2501 new_can_compose_inline));
2502 text_input_type_ = new_type;
2503 can_compose_inline_ = new_can_compose_inline;
2504 text_input_mode_ = new_mode;
2508 #if defined(OS_ANDROID)
2509 void RenderWidget::UpdateTextInputState(bool show_ime_if_needed,
2510 bool send_ime_ack) {
2511 if (handling_ime_event_)
2512 return;
2513 if (!show_ime_if_needed && !input_method_is_active_)
2514 return;
2515 ui::TextInputType new_type = GetTextInputType();
2516 if (IsDateTimeInput(new_type))
2517 return; // Not considered as a text input field in WebKit/Chromium.
2519 blink::WebTextInputInfo new_info;
2520 if (webwidget_)
2521 new_info = webwidget_->textInputInfo();
2523 bool new_can_compose_inline = CanComposeInline();
2525 // Only sends text input params if they are changed or if the ime should be
2526 // shown.
2527 if (show_ime_if_needed || (text_input_type_ != new_type
2528 || text_input_info_ != new_info
2529 || can_compose_inline_ != new_can_compose_inline)) {
2530 ViewHostMsg_TextInputState_Params p;
2531 p.type = new_type;
2532 p.value = new_info.value.utf8();
2533 p.selection_start = new_info.selectionStart;
2534 p.selection_end = new_info.selectionEnd;
2535 p.composition_start = new_info.compositionStart;
2536 p.composition_end = new_info.compositionEnd;
2537 p.can_compose_inline = new_can_compose_inline;
2538 p.show_ime_if_needed = show_ime_if_needed;
2539 p.require_ack = send_ime_ack;
2540 if (p.require_ack)
2541 IncrementOutstandingImeEventAcks();
2542 Send(new ViewHostMsg_TextInputStateChanged(routing_id(), p));
2544 text_input_info_ = new_info;
2545 text_input_type_ = new_type;
2546 can_compose_inline_ = new_can_compose_inline;
2549 #endif
2551 void RenderWidget::GetSelectionBounds(gfx::Rect* focus, gfx::Rect* anchor) {
2552 WebRect focus_webrect;
2553 WebRect anchor_webrect;
2554 webwidget_->selectionBounds(focus_webrect, anchor_webrect);
2555 *focus = focus_webrect;
2556 *anchor = anchor_webrect;
2559 void RenderWidget::UpdateSelectionBounds() {
2560 if (!webwidget_)
2561 return;
2562 if (handling_ime_event_)
2563 return;
2565 ViewHostMsg_SelectionBounds_Params params;
2566 GetSelectionBounds(&params.anchor_rect, &params.focus_rect);
2567 if (selection_anchor_rect_ != params.anchor_rect ||
2568 selection_focus_rect_ != params.focus_rect) {
2569 selection_anchor_rect_ = params.anchor_rect;
2570 selection_focus_rect_ = params.focus_rect;
2571 webwidget_->selectionTextDirection(params.focus_dir, params.anchor_dir);
2572 params.is_anchor_first = webwidget_->isSelectionAnchorFirst();
2573 Send(new ViewHostMsg_SelectionBoundsChanged(routing_id_, params));
2575 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
2576 UpdateCompositionInfo(false);
2577 #endif
2580 // Check blink::WebTextInputType and ui::TextInputType is kept in sync.
2581 COMPILE_ASSERT(int(blink::WebTextInputTypeNone) == \
2582 int(ui::TEXT_INPUT_TYPE_NONE), mismatching_enums);
2583 COMPILE_ASSERT(int(blink::WebTextInputTypeText) == \
2584 int(ui::TEXT_INPUT_TYPE_TEXT), mismatching_enums);
2585 COMPILE_ASSERT(int(blink::WebTextInputTypePassword) == \
2586 int(ui::TEXT_INPUT_TYPE_PASSWORD), mismatching_enums);
2587 COMPILE_ASSERT(int(blink::WebTextInputTypeSearch) == \
2588 int(ui::TEXT_INPUT_TYPE_SEARCH), mismatching_enums);
2589 COMPILE_ASSERT(int(blink::WebTextInputTypeEmail) == \
2590 int(ui::TEXT_INPUT_TYPE_EMAIL), mismatching_enums);
2591 COMPILE_ASSERT(int(blink::WebTextInputTypeNumber) == \
2592 int(ui::TEXT_INPUT_TYPE_NUMBER), mismatching_enums);
2593 COMPILE_ASSERT(int(blink::WebTextInputTypeTelephone) == \
2594 int(ui::TEXT_INPUT_TYPE_TELEPHONE), mismatching_enums);
2595 COMPILE_ASSERT(int(blink::WebTextInputTypeURL) == \
2596 int(ui::TEXT_INPUT_TYPE_URL), mismatching_enums);
2597 COMPILE_ASSERT(int(blink::WebTextInputTypeDate) == \
2598 int(ui::TEXT_INPUT_TYPE_DATE), mismatching_enum);
2599 COMPILE_ASSERT(int(blink::WebTextInputTypeDateTime) == \
2600 int(ui::TEXT_INPUT_TYPE_DATE_TIME), mismatching_enum);
2601 COMPILE_ASSERT(int(blink::WebTextInputTypeDateTimeLocal) == \
2602 int(ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL), mismatching_enum);
2603 COMPILE_ASSERT(int(blink::WebTextInputTypeMonth) == \
2604 int(ui::TEXT_INPUT_TYPE_MONTH), mismatching_enum);
2605 COMPILE_ASSERT(int(blink::WebTextInputTypeTime) == \
2606 int(ui::TEXT_INPUT_TYPE_TIME), mismatching_enum);
2607 COMPILE_ASSERT(int(blink::WebTextInputTypeWeek) == \
2608 int(ui::TEXT_INPUT_TYPE_WEEK), mismatching_enum);
2609 COMPILE_ASSERT(int(blink::WebTextInputTypeTextArea) == \
2610 int(ui::TEXT_INPUT_TYPE_TEXT_AREA), mismatching_enums);
2611 COMPILE_ASSERT(int(blink::WebTextInputTypeContentEditable) == \
2612 int(ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE), mismatching_enums);
2613 COMPILE_ASSERT(int(blink::WebTextInputTypeDateTimeField) == \
2614 int(ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD), mismatching_enums);
2616 ui::TextInputType RenderWidget::WebKitToUiTextInputType(
2617 blink::WebTextInputType type) {
2618 // Check the type is in the range representable by ui::TextInputType.
2619 DCHECK_LE(type, static_cast<int>(ui::TEXT_INPUT_TYPE_MAX)) <<
2620 "blink::WebTextInputType and ui::TextInputType not synchronized";
2621 return static_cast<ui::TextInputType>(type);
2624 ui::TextInputType RenderWidget::GetTextInputType() {
2625 if (webwidget_)
2626 return WebKitToUiTextInputType(webwidget_->textInputInfo().type);
2627 return ui::TEXT_INPUT_TYPE_NONE;
2630 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
2631 void RenderWidget::UpdateCompositionInfo(bool should_update_range) {
2632 gfx::Range range = gfx::Range();
2633 if (should_update_range) {
2634 GetCompositionRange(&range);
2635 } else {
2636 range = composition_range_;
2638 std::vector<gfx::Rect> character_bounds;
2639 GetCompositionCharacterBounds(&character_bounds);
2641 if (!ShouldUpdateCompositionInfo(range, character_bounds))
2642 return;
2643 composition_character_bounds_ = character_bounds;
2644 composition_range_ = range;
2645 Send(new ViewHostMsg_ImeCompositionRangeChanged(
2646 routing_id(), composition_range_, composition_character_bounds_));
2649 void RenderWidget::GetCompositionCharacterBounds(
2650 std::vector<gfx::Rect>* bounds) {
2651 DCHECK(bounds);
2652 bounds->clear();
2655 void RenderWidget::GetCompositionRange(gfx::Range* range) {
2656 size_t location, length;
2657 if (webwidget_->compositionRange(&location, &length)) {
2658 range->set_start(location);
2659 range->set_end(location + length);
2660 } else if (webwidget_->caretOrSelectionRange(&location, &length)) {
2661 range->set_start(location);
2662 range->set_end(location + length);
2663 } else {
2664 *range = gfx::Range::InvalidRange();
2668 bool RenderWidget::ShouldUpdateCompositionInfo(
2669 const gfx::Range& range,
2670 const std::vector<gfx::Rect>& bounds) {
2671 if (composition_range_ != range)
2672 return true;
2673 if (bounds.size() != composition_character_bounds_.size())
2674 return true;
2675 for (size_t i = 0; i < bounds.size(); ++i) {
2676 if (bounds[i] != composition_character_bounds_[i])
2677 return true;
2679 return false;
2681 #endif
2683 bool RenderWidget::CanComposeInline() {
2684 return true;
2687 WebScreenInfo RenderWidget::screenInfo() {
2688 return screen_info_;
2691 float RenderWidget::deviceScaleFactor() {
2692 return device_scale_factor_;
2695 void RenderWidget::resetInputMethod() {
2696 if (!input_method_is_active_)
2697 return;
2699 ImeEventGuard guard(this);
2700 // If the last text input type is not None, then we should finish any
2701 // ongoing composition regardless of the new text input type.
2702 if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE) {
2703 // If a composition text exists, then we need to let the browser process
2704 // to cancel the input method's ongoing composition session.
2705 if (webwidget_->confirmComposition())
2706 Send(new ViewHostMsg_ImeCancelComposition(routing_id()));
2709 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
2710 UpdateCompositionInfo(true);
2711 #endif
2714 void RenderWidget::didHandleGestureEvent(
2715 const WebGestureEvent& event,
2716 bool event_cancelled) {
2717 #if defined(OS_ANDROID)
2718 if (event_cancelled)
2719 return;
2720 if (event.type == WebInputEvent::GestureTap ||
2721 event.type == WebInputEvent::GestureLongPress) {
2722 UpdateTextInputState(true, true);
2724 #endif
2727 void RenderWidget::SchedulePluginMove(const WebPluginGeometry& move) {
2728 size_t i = 0;
2729 for (; i < plugin_window_moves_.size(); ++i) {
2730 if (plugin_window_moves_[i].window == move.window) {
2731 if (move.rects_valid) {
2732 plugin_window_moves_[i] = move;
2733 } else {
2734 plugin_window_moves_[i].visible = move.visible;
2736 break;
2740 if (i == plugin_window_moves_.size())
2741 plugin_window_moves_.push_back(move);
2744 void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) {
2745 for (WebPluginGeometryVector::iterator i = plugin_window_moves_.begin();
2746 i != plugin_window_moves_.end(); ++i) {
2747 if (i->window == window) {
2748 plugin_window_moves_.erase(i);
2749 break;
2754 void RenderWidget::GetRenderingStats(
2755 blink::WebRenderingStatsImpl& stats) const {
2756 if (compositor_)
2757 compositor_->GetRenderingStats(&stats.rendering_stats);
2759 stats.rendering_stats.Add(
2760 legacy_software_mode_stats_->GetRenderingStats());
2763 bool RenderWidget::GetGpuRenderingStats(GpuRenderingStats* stats) const {
2764 GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel();
2765 if (!gpu_channel)
2766 return false;
2768 return gpu_channel->CollectRenderingStatsForSurface(surface_id(), stats);
2771 RenderWidgetCompositor* RenderWidget::compositor() const {
2772 return compositor_.get();
2775 void RenderWidget::OnSetBrowserRenderingStats(
2776 const BrowserRenderingStats& stats) {
2777 browser_rendering_stats_ = stats;
2780 void RenderWidget::GetBrowserRenderingStats(BrowserRenderingStats* stats) {
2781 *stats = browser_rendering_stats_;
2784 bool RenderWidget::WillHandleMouseEvent(const blink::WebMouseEvent& event) {
2785 return false;
2788 bool RenderWidget::WillHandleKeyEvent(const blink::WebKeyboardEvent& event) {
2789 return false;
2792 bool RenderWidget::WillHandleGestureEvent(
2793 const blink::WebGestureEvent& event) {
2794 return false;
2797 void RenderWidget::hasTouchEventHandlers(bool has_handlers) {
2798 Send(new ViewHostMsg_HasTouchEventHandlers(routing_id_, has_handlers));
2801 void RenderWidget::setTouchAction(
2802 blink::WebTouchAction web_touch_action) {
2804 // Ignore setTouchAction calls that result from synthetic touch events (eg.
2805 // when blink is emulating touch with mouse).
2806 if (!handling_touchstart_event_)
2807 return;
2809 // Verify the same values are used by the types so we can cast between them.
2810 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_AUTO) ==
2811 blink::WebTouchActionAuto,
2812 enum_values_must_match_for_touch_action);
2813 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_NONE) ==
2814 blink::WebTouchActionNone,
2815 enum_values_must_match_for_touch_action);
2816 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_PAN_X) ==
2817 blink::WebTouchActionPanX,
2818 enum_values_must_match_for_touch_action);
2819 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_PAN_Y) ==
2820 blink::WebTouchActionPanY,
2821 enum_values_must_match_for_touch_action);
2823 content::TouchAction content_touch_action =
2824 static_cast<content::TouchAction>(web_touch_action);
2825 Send(new InputHostMsg_SetTouchAction(routing_id_, content_touch_action));
2828 bool RenderWidget::HasTouchEventHandlersAt(const gfx::Point& point) const {
2829 return true;
2832 scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
2833 RenderWidget::CreateGraphicsContext3D(
2834 const blink::WebGraphicsContext3D::Attributes& attributes) {
2835 if (!webwidget_)
2836 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
2837 if (CommandLine::ForCurrentProcess()->HasSwitch(
2838 switches::kDisableGpuCompositing))
2839 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
2840 if (!RenderThreadImpl::current())
2841 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
2842 CauseForGpuLaunch cause =
2843 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
2844 scoped_refptr<GpuChannelHost> gpu_channel_host(
2845 RenderThreadImpl::current()->EstablishGpuChannelSync(cause));
2846 if (!gpu_channel_host)
2847 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
2849 WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits;
2850 #if defined(OS_ANDROID)
2851 // If we raster too fast we become upload bound, and pending
2852 // uploads consume memory. For maximum upload throughput, we would
2853 // want to allow for upload_throughput * pipeline_time of pending
2854 // uploads, after which we are just wasting memory. Since we don't
2855 // know our upload throughput yet, this just caps our memory usage.
2856 size_t divider = 1;
2857 if (base::android::SysUtils::IsLowEndDevice())
2858 divider = 6;
2859 // For reference Nexus10 can upload 1MB in about 2.5ms.
2860 const double max_mb_uploaded_per_ms = 2.0 / (5 * divider);
2861 // Deadline to draw a frame to achieve 60 frames per second.
2862 const size_t kMillisecondsPerFrame = 16;
2863 // Assuming a two frame deep pipeline between the CPU and the GPU.
2864 size_t max_transfer_buffer_usage_mb =
2865 static_cast<size_t>(2 * kMillisecondsPerFrame * max_mb_uploaded_per_ms);
2866 static const size_t kBytesPerMegabyte = 1024 * 1024;
2867 // We keep the MappedMemoryReclaimLimit the same as the upload limit
2868 // to avoid unnecessarily stalling the compositor thread.
2869 limits.mapped_memory_reclaim_limit =
2870 max_transfer_buffer_usage_mb * kBytesPerMegabyte;
2871 #endif
2873 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
2874 new WebGraphicsContext3DCommandBufferImpl(
2875 surface_id(),
2876 GetURLForGraphicsContext3D(),
2877 gpu_channel_host.get(),
2878 attributes,
2879 false /* bind generates resources */,
2880 limits));
2881 return context.Pass();
2884 } // namespace content