blob: 187797742e205fe893f4cbfe99e385d6c853c187 [file] [log] [blame]
[email protected]c5218762011-03-24 17:48:511// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]2cff0052011-03-18 16:51:445#include "content/renderer/render_widget.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]32876ae2011-11-15 22:25:217#include "base/bind.h"
[email protected]4fb66842009-12-04 21:41:008#include "base/command_line.h"
[email protected]366ae242011-05-10 02:23:589#include "base/debug/trace_event.h"
initial.commit09911bf2008-07-26 23:55:2910#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1511#include "base/memory/scoped_ptr.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/message_loop.h"
[email protected]835d7c82010-10-14 04:38:3813#include "base/metrics/histogram.h"
[email protected]8a9d6ca32011-06-06 20:11:3014#include "base/utf_string_conversions.h"
[email protected]661eb9d2009-02-03 02:11:4815#include "build/build_config.h"
[email protected]992db4c2011-05-12 15:37:1516#include "content/common/swapped_out_messages.h"
[email protected]778574e2011-03-21 22:03:5017#include "content/common/view_messages.h"
[email protected]c08950d22011-10-13 22:20:2918#include "content/public/common/content_switches.h"
[email protected]3da12cb2011-10-08 02:25:0419#include "content/renderer/gpu/compositor_thread.h"
[email protected]8704f89b2011-04-15 00:30:0520#include "content/renderer/render_process.h"
[email protected]f1a29a02011-10-06 23:08:4421#include "content/renderer/render_thread_impl.h"
[email protected]8d6cba42011-09-02 10:05:1922#include "content/renderer/renderer_webkitplatformsupport_impl.h"
[email protected]484955942010-08-19 16:13:1823#include "ipc/ipc_sync_message.h"
[email protected]661eb9d2009-02-03 02:11:4824#include "skia/ext/platform_canvas.h"
[email protected]d5282e72009-05-13 13:16:5225#include "third_party/skia/include/core/SkShader.h"
[email protected]8bd0fe62011-01-17 06:44:3726#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
[email protected]e99ef6f2011-10-16 01:13:0027#include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h"
[email protected]8bd0fe62011-01-17 06:44:3728#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h"
29#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenuInfo.h"
[email protected]d4cff272011-05-02 15:46:0130#include "third_party/WebKit/Source/WebKit/chromium/public/WebRange.h"
[email protected]8bd0fe62011-01-17 06:44:3731#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h"
32#include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h"
33#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h"
[email protected]8a9d6ca32011-06-06 20:11:3034#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
[email protected]08397d52011-02-05 01:53:3835#include "ui/gfx/point.h"
36#include "ui/gfx/size.h"
[email protected]b9b751f22011-03-25 14:04:1237#include "ui/gfx/surface/transport_dib.h"
[email protected]bd37ae252011-06-03 01:28:1838#include "ui/gfx/gl/gl_switches.h"
[email protected]8c89e7792009-08-19 21:18:3439#include "webkit/glue/webkit_glue.h"
[email protected]191eb3f72010-12-21 06:27:5040#include "webkit/plugins/npapi/webplugin.h"
[email protected]719b36f2010-12-22 20:36:4641#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
[email protected]661eb9d2009-02-03 02:11:4842
43#if defined(OS_POSIX)
[email protected]6b889fb2010-03-23 20:09:4944#include "ipc/ipc_channel_posix.h"
[email protected]d5282e72009-05-13 13:16:5245#include "third_party/skia/include/core/SkPixelRef.h"
46#include "third_party/skia/include/core/SkMallocPixelRef.h"
[email protected]661eb9d2009-02-03 02:11:4847#endif // defined(OS_POSIX)
[email protected]8085dbc82008-09-26 22:53:4448
[email protected]8bd0fe62011-01-17 06:44:3749#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h"
initial.commit09911bf2008-07-26 23:55:2950
[email protected]fa7b1dc2010-06-23 17:53:0451using WebKit::WebCompositionUnderline;
[email protected]7c51b0ee2009-07-08 21:49:3052using WebKit::WebCursorInfo;
[email protected]62cb33cae2009-03-27 23:30:2253using WebKit::WebInputEvent;
[email protected]6a8ddba52010-09-05 04:38:0654using WebKit::WebMouseEvent;
[email protected]4873c7d2009-07-16 06:36:2855using WebKit::WebNavigationPolicy;
[email protected]e99ef6f2011-10-16 01:13:0056using WebKit::WebPoint;
[email protected]4873c7d2009-07-16 06:36:2857using WebKit::WebPopupMenu;
[email protected]88efb7ec2009-07-14 16:32:5958using WebKit::WebPopupMenuInfo;
[email protected]484955942010-08-19 16:13:1859using WebKit::WebPopupType;
[email protected]d4cff272011-05-02 15:46:0160using WebKit::WebRange;
[email protected]b3f2b912009-04-09 16:18:5261using WebKit::WebRect;
[email protected]12456fa2009-04-01 23:07:1962using WebKit::WebScreenInfo;
[email protected]b3f2b912009-04-09 16:18:5263using WebKit::WebSize;
[email protected]4873c7d2009-07-16 06:36:2864using WebKit::WebTextDirection;
[email protected]2d0f2e92011-10-03 09:02:2465using WebKit::WebTouchEvent;
[email protected]fa7b1dc2010-06-23 17:53:0466using WebKit::WebVector;
[email protected]484955942010-08-19 16:13:1867using WebKit::WebWidget;
[email protected]380244092011-10-07 17:26:2768using content::RenderThread;
[email protected]62cb33cae2009-03-27 23:30:2269
[email protected]380244092011-10-07 17:26:2770RenderWidget::RenderWidget(WebKit::WebPopupType popup_type)
initial.commit09911bf2008-07-26 23:55:2971 : routing_id_(MSG_ROUTING_NONE),
[email protected]c5b3b5e2009-02-13 06:41:1172 webwidget_(NULL),
initial.commit09911bf2008-07-26 23:55:2973 opener_id_(MSG_ROUTING_NONE),
[email protected]659f73f2009-10-13 13:43:4274 host_window_(0),
[email protected]b4d08452010-10-05 17:34:3575 current_paint_buf_(NULL),
initial.commit09911bf2008-07-26 23:55:2976 next_paint_flags_(0),
[email protected]0cff69e2011-11-22 22:26:0677 filtered_time_per_frame_(0.0f),
[email protected]53d3f302009-12-21 04:42:0578 update_reply_pending_(false),
[email protected]65225772011-05-12 21:10:2479 using_asynchronous_swapbuffers_(false),
80 num_swapbuffers_complete_pending_(0),
initial.commit09911bf2008-07-26 23:55:2981 did_show_(false),
initial.commit09911bf2008-07-26 23:55:2982 is_hidden_(false),
[email protected]ee41e7d22011-10-14 19:34:0983 is_fullscreen_(false),
initial.commit09911bf2008-07-26 23:55:2984 needs_repainting_on_restore_(false),
85 has_focus_(false),
[email protected]5dd768212009-08-13 23:34:4986 handling_input_event_(false),
[email protected]661eb9d2009-02-03 02:11:4887 closing_(false),
[email protected]992db4c2011-05-12 15:37:1588 is_swapped_out_(false),
[email protected]fa7b1dc2010-06-23 17:53:0489 input_method_is_active_(false),
[email protected]ad26ef42011-06-17 07:59:4590 text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
91 can_compose_inline_(true),
[email protected]3e2b375b2010-04-07 17:03:1292 popup_type_(popup_type),
[email protected]867125a02009-12-10 06:01:4893 pending_window_rect_count_(0),
[email protected]edbcde932010-05-07 17:10:4694 suppress_next_char_events_(false),
[email protected]5f8b1022011-01-21 23:34:5095 is_accelerated_compositing_active_(false),
[email protected]ee3d3ad2011-02-04 00:42:2196 animation_update_pending_(false),
[email protected]65225772011-05-12 21:10:2497 animation_task_posted_(false),
98 invalidation_task_posted_(false) {
[email protected]8930d472009-02-21 08:05:2899 RenderProcess::current()->AddRefProcess();
[email protected]380244092011-10-07 17:26:27100 DCHECK(RenderThread::Get());
[email protected]bd37ae252011-06-03 01:28:18101 has_disable_gpu_vsync_switch_ = CommandLine::ForCurrentProcess()->HasSwitch(
102 switches::kDisableGpuVsync);
initial.commit09911bf2008-07-26 23:55:29103}
104
105RenderWidget::~RenderWidget() {
[email protected]c5b3b5e2009-02-13 06:41:11106 DCHECK(!webwidget_) << "Leaking our WebWidget!";
[email protected]b4d08452010-10-05 17:34:35107 if (current_paint_buf_) {
108 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
109 current_paint_buf_ = NULL;
initial.commit09911bf2008-07-26 23:55:29110 }
[email protected]992db4c2011-05-12 15:37:15111 // If we are swapped out, we have released already.
112 if (!is_swapped_out_)
113 RenderProcess::current()->ReleaseProcess();
initial.commit09911bf2008-07-26 23:55:29114}
115
[email protected]484955942010-08-19 16:13:18116// static
[email protected]8085dbc82008-09-26 22:53:44117RenderWidget* RenderWidget::Create(int32 opener_id,
[email protected]3e2b375b2010-04-07 17:03:12118 WebKit::WebPopupType popup_type) {
initial.commit09911bf2008-07-26 23:55:29119 DCHECK(opener_id != MSG_ROUTING_NONE);
[email protected]380244092011-10-07 17:26:27120 scoped_refptr<RenderWidget> widget(new RenderWidget(popup_type));
initial.commit09911bf2008-07-26 23:55:29121 widget->Init(opener_id); // adds reference
122 return widget;
123}
124
[email protected]484955942010-08-19 16:13:18125// static
126WebWidget* RenderWidget::CreateWebWidget(RenderWidget* render_widget) {
127 switch (render_widget->popup_type_) {
[email protected]e2356242010-11-16 22:33:03128 case WebKit::WebPopupTypeNone: // Nothing to create.
[email protected]484955942010-08-19 16:13:18129 break;
130 case WebKit::WebPopupTypeSelect:
131 case WebKit::WebPopupTypeSuggestion:
132 return WebPopupMenu::create(render_widget);
133 default:
134 NOTREACHED();
135 }
136 return NULL;
137}
138
initial.commit09911bf2008-07-26 23:55:29139void RenderWidget::Init(int32 opener_id) {
[email protected]484955942010-08-19 16:13:18140 DoInit(opener_id,
141 RenderWidget::CreateWebWidget(this),
142 new ViewHostMsg_CreateWidget(opener_id, popup_type_, &routing_id_));
143}
144
[email protected]484955942010-08-19 16:13:18145void RenderWidget::DoInit(int32 opener_id,
[email protected]6a8ddba52010-09-05 04:38:06146 WebWidget* web_widget,
[email protected]484955942010-08-19 16:13:18147 IPC::SyncMessage* create_widget_message) {
initial.commit09911bf2008-07-26 23:55:29148 DCHECK(!webwidget_);
149
150 if (opener_id != MSG_ROUTING_NONE)
151 opener_id_ = opener_id;
152
[email protected]484955942010-08-19 16:13:18153 webwidget_ = web_widget;
initial.commit09911bf2008-07-26 23:55:29154
[email protected]380244092011-10-07 17:26:27155 bool result = RenderThread::Get()->Send(create_widget_message);
initial.commit09911bf2008-07-26 23:55:29156 if (result) {
[email protected]380244092011-10-07 17:26:27157 RenderThread::Get()->AddRoute(routing_id_, this);
initial.commit09911bf2008-07-26 23:55:29158 // Take a reference on behalf of the RenderThread. This will be balanced
159 // when we receive ViewMsg_Close.
160 AddRef();
161 } else {
162 DCHECK(false);
163 }
164}
165
166// This is used to complete pending inits and non-pending inits. For non-
167// pending cases, the parent will be the same as the current parent. This
168// indicates we do not need to reparent or anything.
[email protected]2d7c8552011-06-27 19:21:55169void RenderWidget::CompleteInit(gfx::NativeViewId parent_hwnd) {
initial.commit09911bf2008-07-26 23:55:29170 DCHECK(routing_id_ != MSG_ROUTING_NONE);
initial.commit09911bf2008-07-26 23:55:29171
172 host_window_ = parent_hwnd;
173
[email protected]6de74452009-02-25 18:04:59174 Send(new ViewHostMsg_RenderViewReady(routing_id_));
initial.commit09911bf2008-07-26 23:55:29175}
176
[email protected]992db4c2011-05-12 15:37:15177void RenderWidget::SetSwappedOut(bool is_swapped_out) {
178 // We should only toggle between states.
179 DCHECK(is_swapped_out_ != is_swapped_out);
180 is_swapped_out_ = is_swapped_out;
181
182 // If we are swapping out, we will call ReleaseProcess, allowing the process
183 // to exit if all of its RenderViews are swapped out. We wait until the
184 // WasSwappedOut call to do this, to avoid showing the sad tab.
185 // If we are swapping in, we call AddRefProcess to prevent the process from
186 // exiting.
187 if (!is_swapped_out)
188 RenderProcess::current()->AddRefProcess();
189}
190
[email protected]a95986a82010-12-24 06:19:28191bool RenderWidget::OnMessageReceived(const IPC::Message& message) {
192 bool handled = true;
193 IPC_BEGIN_MESSAGE_MAP(RenderWidget, message)
194 IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
195 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
196 IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize)
197 IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden)
198 IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored)
[email protected]992db4c2011-05-12 15:37:15199 IPC_MESSAGE_HANDLER(ViewMsg_WasSwappedOut, OnWasSwappedOut)
[email protected]a95986a82010-12-24 06:19:28200 IPC_MESSAGE_HANDLER(ViewMsg_UpdateRect_ACK, OnUpdateRectAck)
201 IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent)
202 IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost)
203 IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus)
204 IPC_MESSAGE_HANDLER(ViewMsg_SetInputMethodActive, OnSetInputMethodActive)
205 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition)
206 IPC_MESSAGE_HANDLER(ViewMsg_ImeConfirmComposition, OnImeConfirmComposition)
207 IPC_MESSAGE_HANDLER(ViewMsg_PaintAtSize, OnMsgPaintAtSize)
208 IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint)
209 IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection)
210 IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck)
211 IPC_MESSAGE_UNHANDLED(handled = false)
212 IPC_END_MESSAGE_MAP()
213 return handled;
214}
initial.commit09911bf2008-07-26 23:55:29215
216bool RenderWidget::Send(IPC::Message* message) {
[email protected]992db4c2011-05-12 15:37:15217 // Don't send any messages after the browser has told us to close, and filter
218 // most outgoing messages while swapped out.
219 if ((is_swapped_out_ &&
220 !content::SwappedOutMessages::CanSendWhileSwappedOut(message)) ||
221 closing_) {
initial.commit09911bf2008-07-26 23:55:29222 delete message;
223 return false;
224 }
225
226 // If given a messsage without a routing ID, then assign our routing ID.
227 if (message->routing_id() == MSG_ROUTING_NONE)
228 message->set_routing_id(routing_id_);
229
[email protected]380244092011-10-07 17:26:27230 return RenderThread::Get()->Send(message);
[email protected]8085dbc82008-09-26 22:53:44231}
232
initial.commit09911bf2008-07-26 23:55:29233// Got a response from the browser after the renderer decided to create a new
234// view.
[email protected]c03a6e72011-04-19 21:42:06235void RenderWidget::OnCreatingNewAck(
[email protected]2d7c8552011-06-27 19:21:55236 gfx::NativeViewId parent) {
initial.commit09911bf2008-07-26 23:55:29237 DCHECK(routing_id_ != MSG_ROUTING_NONE);
238
[email protected]2d7c8552011-06-27 19:21:55239 CompleteInit(parent);
initial.commit09911bf2008-07-26 23:55:29240}
241
242void RenderWidget::OnClose() {
243 if (closing_)
244 return;
245 closing_ = true;
246
247 // Browser correspondence is no longer needed at this point.
[email protected]bee16aab2009-08-26 15:55:03248 if (routing_id_ != MSG_ROUTING_NONE) {
[email protected]380244092011-10-07 17:26:27249 RenderThread::Get()->RemoveRoute(routing_id_);
[email protected]bee16aab2009-08-26 15:55:03250 SetHidden(false);
251 }
initial.commit09911bf2008-07-26 23:55:29252
initial.commit09911bf2008-07-26 23:55:29253 // If there is a Send call on the stack, then it could be dangerous to close
[email protected]d3fc25652009-02-24 22:31:25254 // now. Post a task that only gets invoked when there are no nested message
255 // loops.
[email protected]32876ae2011-11-15 22:25:21256 MessageLoop::current()->PostNonNestableTask(
257 FROM_HERE, NewRunnableMethod(this, &RenderWidget::Close));
[email protected]d3fc25652009-02-24 22:31:25258
259 // Balances the AddRef taken when we called AddRoute.
260 Release();
initial.commit09911bf2008-07-26 23:55:29261}
262
[email protected]f21c613a2009-02-12 14:46:17263void RenderWidget::OnResize(const gfx::Size& new_size,
[email protected]ee41e7d22011-10-14 19:34:09264 const gfx::Rect& resizer_rect,
265 bool is_fullscreen) {
initial.commit09911bf2008-07-26 23:55:29266 // During shutdown we can just ignore this message.
267 if (!webwidget_)
268 return;
269
[email protected]e2356242010-11-16 22:33:03270 // We shouldn't be asked to resize to our current size.
271 DCHECK(size_ != new_size || resizer_rect_ != resizer_rect);
272
[email protected]f21c613a2009-02-12 14:46:17273 // Remember the rect where the resize corner will be drawn.
274 resizer_rect_ = resizer_rect;
275
[email protected]2b624c562011-10-27 22:58:26276 // NOTE: We may have entered fullscreen mode without changing our size.
277 bool fullscreen_change = is_fullscreen_ != is_fullscreen;
278 if (fullscreen_change)
279 WillToggleFullscreen();
[email protected]ee41e7d22011-10-14 19:34:09280 is_fullscreen_ = is_fullscreen;
initial.commit09911bf2008-07-26 23:55:29281
[email protected]2b624c562011-10-27 22:58:26282 if (size_ != new_size) {
283 // TODO(darin): We should not need to reset this here.
284 SetHidden(false);
285 needs_repainting_on_restore_ = false;
initial.commit09911bf2008-07-26 23:55:29286
[email protected]2b624c562011-10-27 22:58:26287 size_ = new_size;
[email protected]552e6002009-11-19 05:24:57288
[email protected]2b624c562011-10-27 22:58:26289 // We should not be sent a Resize message if we have not ACK'd the previous
290 DCHECK(!next_paint_is_resize_ack());
291
292 paint_aggregator_.ClearPendingUpdate();
293
294 // When resizing, we want to wait to paint before ACK'ing the resize. This
295 // ensures that we only resize as fast as we can paint. We only need to
296 // send an ACK if we are resized to a non-empty rect.
297 webwidget_->resize(new_size);
298 if (!new_size.IsEmpty()) {
299 if (!is_accelerated_compositing_active_) {
300 // Resize should have caused an invalidation of the entire view.
301 DCHECK(paint_aggregator_.HasPendingUpdate());
302 }
303
304 // We will send the Resize_ACK flag once we paint again.
305 set_next_paint_is_resize_ack();
[email protected]f98d7e3c2010-09-13 22:30:46306 }
initial.commit09911bf2008-07-26 23:55:29307 }
[email protected]2b624c562011-10-27 22:58:26308
309 if (fullscreen_change)
310 DidToggleFullscreen();
initial.commit09911bf2008-07-26 23:55:29311}
312
313void RenderWidget::OnWasHidden() {
[email protected]9c3085f2011-06-09 02:10:31314 TRACE_EVENT0("renderer", "RenderWidget::OnWasHidden");
initial.commit09911bf2008-07-26 23:55:29315 // Go into a mode where we stop generating paint and scrolling events.
[email protected]bee16aab2009-08-26 15:55:03316 SetHidden(true);
initial.commit09911bf2008-07-26 23:55:29317}
318
319void RenderWidget::OnWasRestored(bool needs_repainting) {
[email protected]9c3085f2011-06-09 02:10:31320 TRACE_EVENT0("renderer", "RenderWidget::OnWasRestored");
initial.commit09911bf2008-07-26 23:55:29321 // During shutdown we can just ignore this message.
322 if (!webwidget_)
323 return;
324
325 // See OnWasHidden
[email protected]bee16aab2009-08-26 15:55:03326 SetHidden(false);
initial.commit09911bf2008-07-26 23:55:29327
328 if (!needs_repainting && !needs_repainting_on_restore_)
329 return;
330 needs_repainting_on_restore_ = false;
331
[email protected]d65adb12010-04-28 17:26:49332 // Tag the next paint as a restore ack, which is picked up by
333 // DoDeferredUpdate when it sends out the next PaintRect message.
initial.commit09911bf2008-07-26 23:55:29334 set_next_paint_is_restore_ack();
335
336 // Generate a full repaint.
[email protected]a79d8a632010-11-18 22:35:56337 if (!is_accelerated_compositing_active_) {
[email protected]f98d7e3c2010-09-13 22:30:46338 didInvalidateRect(gfx::Rect(size_.width(), size_.height()));
339 } else {
340 scheduleComposite();
341 }
initial.commit09911bf2008-07-26 23:55:29342}
343
[email protected]992db4c2011-05-12 15:37:15344void RenderWidget::OnWasSwappedOut() {
345 // If we have been swapped out and no one else is using this process,
346 // it's safe to exit now. If we get swapped back in, we will call
347 // AddRefProcess in SetSwappedOut.
348 if (is_swapped_out_)
349 RenderProcess::current()->ReleaseProcess();
350}
351
[email protected]53d3f302009-12-21 04:42:05352void RenderWidget::OnRequestMoveAck() {
353 DCHECK(pending_window_rect_count_);
354 pending_window_rect_count_--;
355}
356
357void RenderWidget::OnUpdateRectAck() {
[email protected]366ae242011-05-10 02:23:58358 TRACE_EVENT0("renderer", "RenderWidget::OnUpdateRectAck");
[email protected]53d3f302009-12-21 04:42:05359 DCHECK(update_reply_pending());
360 update_reply_pending_ = false;
361
[email protected]b4d08452010-10-05 17:34:35362 // If we sent an UpdateRect message with a zero-sized bitmap, then we should
363 // have no current paint buffer.
364 if (current_paint_buf_) {
365 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
366 current_paint_buf_ = NULL;
367 }
368
[email protected]65225772011-05-12 21:10:24369 // If swapbuffers is still pending, then defer the update until the
370 // swapbuffers occurs.
371 if (num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) {
372 TRACE_EVENT0("renderer", "EarlyOut_SwapStillPending");
373 return;
374 }
375
[email protected]00c39612010-03-06 02:53:28376 // Notify subclasses.
377 DidFlushPaint();
[email protected]a2f6bc112009-06-27 16:27:25378
initial.commit09911bf2008-07-26 23:55:29379 // Continue painting if necessary...
[email protected]65225772011-05-12 21:10:24380 DoDeferredUpdateAndSendInputAck();
381}
382
383bool RenderWidget::SupportsAsynchronousSwapBuffers()
384{
385 return false;
386}
387
388void RenderWidget::OnSwapBuffersAborted()
389{
390 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersAborted");
391 num_swapbuffers_complete_pending_ = 0;
392 using_asynchronous_swapbuffers_ = false;
393 // Schedule another frame so the compositor learns about it.
394 scheduleComposite();
395}
396
[email protected]37a6f302011-07-11 23:43:08397void RenderWidget::OnSwapBuffersPosted() {
398 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersPosted");
399 if (using_asynchronous_swapbuffers_)
400 num_swapbuffers_complete_pending_++;
401}
402
403void RenderWidget::OnSwapBuffersComplete() {
[email protected]65225772011-05-12 21:10:24404 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersComplete");
405 // When compositing deactivates, we reset the swapbuffers pending count. The
406 // swapbuffers acks may still arrive, however.
407 if (num_swapbuffers_complete_pending_ == 0) {
408 TRACE_EVENT0("renderer", "EarlyOut_ZeroSwapbuffersPending");
409 return;
410 }
411 num_swapbuffers_complete_pending_--;
412
413 // If update reply is still pending, then defer the update until that reply
414 // occurs.
415 if (update_reply_pending_){
416 TRACE_EVENT0("renderer", "EarlyOut_UpdateReplyPending");
417 return;
418 }
419
420 // If we are not accelerated rendering, then this is a stale swapbuffers from
[email protected]50312bf2011-06-22 23:30:06421 // when we were previously rendering. However, if an invalidation task is not
422 // posted, there may be software rendering work pending. In that case, don't
423 // early out.
424 if (!is_accelerated_compositing_active_ && invalidation_task_posted_) {
[email protected]65225772011-05-12 21:10:24425 TRACE_EVENT0("renderer", "EarlyOut_AcceleratedCompositingOff");
426 return;
427 }
428
429 // Notify subclasses.
[email protected]50312bf2011-06-22 23:30:06430 if(is_accelerated_compositing_active_)
431 DidFlushPaint();
[email protected]65225772011-05-12 21:10:24432
433 // Continue painting if necessary...
434 DoDeferredUpdateAndSendInputAck();
initial.commit09911bf2008-07-26 23:55:29435}
436
initial.commit09911bf2008-07-26 23:55:29437void RenderWidget::OnHandleInputEvent(const IPC::Message& message) {
[email protected]65225772011-05-12 21:10:24438 TRACE_EVENT0("renderer", "RenderWidget::OnHandleInputEvent");
initial.commit09911bf2008-07-26 23:55:29439 void* iter = NULL;
440
441 const char* data;
442 int data_length;
[email protected]5dd768212009-08-13 23:34:49443 handling_input_event_ = true;
444 if (!message.ReadData(&iter, &data, &data_length)) {
445 handling_input_event_ = false;
initial.commit09911bf2008-07-26 23:55:29446 return;
[email protected]5dd768212009-08-13 23:34:49447 }
initial.commit09911bf2008-07-26 23:55:29448
449 const WebInputEvent* input_event =
450 reinterpret_cast<const WebInputEvent*>(data);
[email protected]867125a02009-12-10 06:01:48451
452 bool is_keyboard_shortcut = false;
453 // is_keyboard_shortcut flag is only available for RawKeyDown events.
454 if (input_event->type == WebInputEvent::RawKeyDown)
455 message.ReadBool(&iter, &is_keyboard_shortcut);
456
[email protected]67bfb83f2011-09-22 03:36:37457 bool prevent_default = false;
458 if (WebInputEvent::isMouseEventType(input_event->type)) {
459 prevent_default = WillHandleMouseEvent(
460 *(static_cast<const WebMouseEvent*>(input_event)));
461 }
462
463 bool processed = prevent_default;
[email protected]867125a02009-12-10 06:01:48464 if (input_event->type != WebInputEvent::Char || !suppress_next_char_events_) {
465 suppress_next_char_events_ = false;
[email protected]67bfb83f2011-09-22 03:36:37466 if (!processed && webwidget_)
[email protected]867125a02009-12-10 06:01:48467 processed = webwidget_->handleInputEvent(*input_event);
468 }
469
470 // If this RawKeyDown event corresponds to a browser keyboard shortcut and
471 // it's not processed by webkit, then we need to suppress the upcoming Char
472 // events.
473 if (!processed && is_keyboard_shortcut)
474 suppress_next_char_events_ = true;
initial.commit09911bf2008-07-26 23:55:29475
[email protected]a9fb30aa2011-10-06 06:58:46476 IPC::Message* response =
477 new ViewHostMsg_HandleInputEvent_ACK(routing_id_, input_event->type,
478 processed);
[email protected]e2824412009-02-27 01:57:05479
[email protected]353a34c2010-05-28 23:35:17480 if ((input_event->type == WebInputEvent::MouseMove ||
[email protected]d93fc462011-03-14 23:03:03481 input_event->type == WebInputEvent::MouseWheel ||
482 input_event->type == WebInputEvent::TouchMove) &&
[email protected]552e6002009-11-19 05:24:57483 paint_aggregator_.HasPendingUpdate()) {
[email protected]12fbad812009-09-01 18:21:24484 // We want to rate limit the input events in this case, so we'll wait for
485 // painting to finish before ACKing this message.
[email protected]353a34c2010-05-28 23:35:17486 if (pending_input_event_ack_.get()) {
487 // As two different kinds of events could cause us to postpone an ack
488 // we send it now, if we have one pending. The Browser should never
489 // send us the same kind of event we are delaying the ack for.
490 Send(pending_input_event_ack_.release());
491 }
[email protected]12fbad812009-09-01 18:21:24492 pending_input_event_ack_.reset(response);
493 } else {
494 Send(response);
495 }
496
[email protected]5dd768212009-08-13 23:34:49497 handling_input_event_ = false;
[email protected]446705872009-09-10 07:22:48498
[email protected]67bfb83f2011-09-22 03:36:37499 if (!prevent_default) {
500 if (WebInputEvent::isKeyboardEventType(input_event->type))
501 DidHandleKeyEvent();
502 if (WebInputEvent::isMouseEventType(input_event->type))
503 DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event)));
[email protected]2d0f2e92011-10-03 09:02:24504 if (WebInputEvent::isTouchEventType(input_event->type))
505 DidHandleTouchEvent(*(static_cast<const WebTouchEvent*>(input_event)));
[email protected]67bfb83f2011-09-22 03:36:37506 }
initial.commit09911bf2008-07-26 23:55:29507}
508
509void RenderWidget::OnMouseCaptureLost() {
510 if (webwidget_)
[email protected]4873c7d2009-07-16 06:36:28511 webwidget_->mouseCaptureLost();
initial.commit09911bf2008-07-26 23:55:29512}
513
514void RenderWidget::OnSetFocus(bool enable) {
515 has_focus_ = enable;
[email protected]9d166af2010-03-02 22:04:33516 if (webwidget_)
517 webwidget_->setFocus(enable);
initial.commit09911bf2008-07-26 23:55:29518}
519
520void RenderWidget::ClearFocus() {
521 // We may have got the focus from the browser before this gets processed, in
522 // which case we do not want to unfocus ourself.
523 if (!has_focus_ && webwidget_)
[email protected]4873c7d2009-07-16 06:36:28524 webwidget_->setFocus(false);
initial.commit09911bf2008-07-26 23:55:29525}
526
[email protected]2d5d09d52009-06-15 14:29:21527void RenderWidget::PaintRect(const gfx::Rect& rect,
[email protected]4fb66842009-12-04 21:41:00528 const gfx::Point& canvas_origin,
[email protected]2d5d09d52009-06-15 14:29:21529 skia::PlatformCanvas* canvas) {
[email protected]50312bf2011-06-22 23:30:06530 TRACE_EVENT2("renderer", "PaintRect",
531 "width", rect.width(), "height", rect.height());
[email protected]4fb66842009-12-04 21:41:00532 canvas->save();
[email protected]2d5d09d52009-06-15 14:29:21533
534 // Bring the canvas into the coordinate system of the paint rect.
[email protected]4fb66842009-12-04 21:41:00535 canvas->translate(static_cast<SkScalar>(-canvas_origin.x()),
536 static_cast<SkScalar>(-canvas_origin.y()));
[email protected]96c3499a2009-05-02 18:31:03537
[email protected]699ab0d2009-04-23 23:19:14538 // If there is a custom background, tile it.
539 if (!background_.empty()) {
[email protected]699ab0d2009-04-23 23:19:14540 SkPaint paint;
541 SkShader* shader = SkShader::CreateBitmapShader(background_,
542 SkShader::kRepeat_TileMode,
543 SkShader::kRepeat_TileMode);
544 paint.setShader(shader)->unref();
[email protected]fb10ec5b2011-10-24 17:54:20545
546 // Use kSrc_Mode to handle background_ transparency properly.
547 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
548
549 // Canvas could contain multiple update rects. Clip to given rect so that
550 // we don't accidentally clear other update rects.
551 canvas->save();
552 SkRect clip;
553 clip.set(SkIntToScalar(rect.x()), SkIntToScalar(rect.y()),
554 SkIntToScalar(rect.right()), SkIntToScalar(rect.bottom()));
555 canvas->clipRect(clip);
[email protected]699ab0d2009-04-23 23:19:14556 canvas->drawPaint(paint);
[email protected]fb10ec5b2011-10-24 17:54:20557 canvas->restore();
[email protected]699ab0d2009-04-23 23:19:14558 }
559
[email protected]719b36f2010-12-22 20:36:46560 // First see if this rect is a plugin that can paint itself faster.
561 TransportDIB* optimized_dib = NULL;
562 gfx::Rect optimized_copy_rect, optimized_copy_location;
563 webkit::ppapi::PluginInstance* optimized_instance =
564 GetBitmapForOptimizedPluginPaint(rect, &optimized_dib,
565 &optimized_copy_location,
566 &optimized_copy_rect);
567 if (optimized_instance) {
568 // This plugin can be optimize-painted and we can just ask it to paint
569 // itself. We don't actually need the TransportDIB in this case.
570 //
571 // This is an optimization for PPAPI plugins that know they're on top of
572 // the page content. If this rect is inside such a plugin, we can save some
573 // time and avoid re-rendering the page content which we know will be
574 // covered by the plugin later (this time can be significant, especially
575 // for a playing movie that is invalidating a lot).
576 //
577 // In the plugin movie case, hopefully the similar call to
578 // GetBitmapForOptimizedPluginPaint in DoDeferredUpdate handles the
579 // painting, because that avoids copying the plugin image to a different
580 // paint rect. Unfortunately, if anything on the page is animating other
581 // than the movie, it break this optimization since the union of the
582 // invalid regions will be larger than the plugin.
583 //
584 // This code optimizes that case, where we can still avoid painting in
585 // WebKit and filling the background (which can be slow) and just painting
586 // the plugin. Unlike the DoDeferredUpdate case, an extra copy is still
587 // required.
588 optimized_instance->Paint(webkit_glue::ToWebCanvas(canvas),
[email protected]2df1b362011-01-21 21:22:27589 optimized_copy_location, rect);
[email protected]719b36f2010-12-22 20:36:46590 } else {
591 // Normal painting case.
592 webwidget_->paint(webkit_glue::ToWebCanvas(canvas), rect);
593
594 // Flush to underlying bitmap. TODO(darin): is this needed?
[email protected]62f2e802011-05-26 14:28:35595 skia::GetTopDevice(*canvas)->accessBitmap(false);
[email protected]719b36f2010-12-22 20:36:46596 }
initial.commit09911bf2008-07-26 23:55:29597
[email protected]4fb66842009-12-04 21:41:00598 PaintDebugBorder(rect, canvas);
[email protected]4fb66842009-12-04 21:41:00599 canvas->restore();
600}
601
602void RenderWidget::PaintDebugBorder(const gfx::Rect& rect,
603 skia::PlatformCanvas* canvas) {
604 static bool kPaintBorder =
605 CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowPaintRects);
606 if (!kPaintBorder)
607 return;
608
[email protected]53d3f302009-12-21 04:42:05609 // Cycle through these colors to help distinguish new paint rects.
610 const SkColor colors[] = {
611 SkColorSetARGB(0x3F, 0xFF, 0, 0),
612 SkColorSetARGB(0x3F, 0xFF, 0, 0xFF),
613 SkColorSetARGB(0x3F, 0, 0, 0xFF),
614 };
615 static int color_selector = 0;
616
[email protected]4fb66842009-12-04 21:41:00617 SkPaint paint;
618 paint.setStyle(SkPaint::kStroke_Style);
[email protected]53d3f302009-12-21 04:42:05619 paint.setColor(colors[color_selector++ % arraysize(colors)]);
[email protected]4fb66842009-12-04 21:41:00620 paint.setStrokeWidth(1);
621
622 SkIRect irect;
623 irect.set(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1);
624 canvas->drawIRect(irect, paint);
initial.commit09911bf2008-07-26 23:55:29625}
626
[email protected]52ccd0ea2011-02-16 01:09:05627void RenderWidget::AnimationCallback() {
[email protected]921244e42011-07-20 16:36:30628 TRACE_EVENT0("renderer", "RenderWidget::AnimationCallback");
[email protected]52ccd0ea2011-02-16 01:09:05629 animation_task_posted_ = false;
[email protected]921244e42011-07-20 16:36:30630 if (!animation_update_pending_) {
631 TRACE_EVENT0("renderer", "EarlyOut_NoAnimationUpdatePending");
[email protected]7c4329e2011-02-18 22:02:59632 return;
[email protected]921244e42011-07-20 16:36:30633 }
[email protected]bd37ae252011-06-03 01:28:18634 if (!animation_floor_time_.is_null() && IsRenderingVSynced()) {
[email protected]7c4329e2011-02-18 22:02:59635 // Record when we fired (according to base::Time::Now()) relative to when
636 // we posted the task to quantify how much the base::Time/base::TimeTicks
637 // skew is affecting animations.
638 base::TimeDelta animation_callback_delay = base::Time::Now() -
639 (animation_floor_time_ - base::TimeDelta::FromMilliseconds(16));
640 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.AnimationCallbackDelayTime",
641 animation_callback_delay,
642 base::TimeDelta::FromMilliseconds(0),
643 base::TimeDelta::FromMilliseconds(30),
644 25);
645 }
[email protected]65225772011-05-12 21:10:24646 DoDeferredUpdateAndSendInputAck();
[email protected]12fbad812009-09-01 18:21:24647}
648
[email protected]52ccd0ea2011-02-16 01:09:05649void RenderWidget::AnimateIfNeeded() {
[email protected]7c4329e2011-02-18 22:02:59650 if (!animation_update_pending_)
651 return;
[email protected]bd37ae252011-06-03 01:28:18652
653 // Target 60FPS if vsync is on. Go as fast as we can if vsync is off.
654 int animationInterval = IsRenderingVSynced() ? 16 : 0;
655
[email protected]7c4329e2011-02-18 22:02:59656 base::Time now = base::Time::Now();
657 if (now >= animation_floor_time_) {
[email protected]921244e42011-07-20 16:36:30658 TRACE_EVENT0("renderer", "RenderWidget::AnimateIfNeeded")
[email protected]bd37ae252011-06-03 01:28:18659 animation_floor_time_ = now +
660 base::TimeDelta::FromMilliseconds(animationInterval);
661 // Set a timer to call us back after animationInterval before
[email protected]7c4329e2011-02-18 22:02:59662 // running animation callbacks so that if a callback requests another
663 // we'll be sure to run it at the proper time.
[email protected]32876ae2011-11-15 22:25:21664 MessageLoop::current()->PostDelayedTask(
665 FROM_HERE, base::Bind(&RenderWidget::AnimationCallback, this),
666 animationInterval);
[email protected]7c4329e2011-02-18 22:02:59667 animation_task_posted_ = true;
668 animation_update_pending_ = false;
[email protected]a5922cc2011-05-24 23:06:30669 webwidget_->animate(0.0);
[email protected]7c4329e2011-02-18 22:02:59670 return;
[email protected]5f8b1022011-01-21 23:34:50671 }
[email protected]bd37ae252011-06-03 01:28:18672 TRACE_EVENT0("renderer", "EarlyOut_AnimatedTooRecently");
[email protected]7c4329e2011-02-18 22:02:59673 if (animation_task_posted_)
674 return;
675 // This code uses base::Time::Now() to calculate the floor and next fire
676 // time because javascript's Date object uses base::Time::Now(). The
677 // message loop uses base::TimeTicks, which on windows can have a
678 // different granularity than base::Time.
679 // The upshot of all this is that this function might be called before
680 // base::Time::Now() has advanced past the animation_floor_time_. To
681 // avoid exposing this delay to javascript, we keep posting delayed
682 // tasks until base::Time::Now() has advanced far enough.
683 int64 delay = (animation_floor_time_ - now).InMillisecondsRoundedUp();
684 animation_task_posted_ = true;
[email protected]32876ae2011-11-15 22:25:21685 MessageLoop::current()->PostDelayedTask(
686 FROM_HERE, base::Bind(&RenderWidget::AnimationCallback, this), delay);
[email protected]5f8b1022011-01-21 23:34:50687}
688
[email protected]bd37ae252011-06-03 01:28:18689bool RenderWidget::IsRenderingVSynced() {
690 // TODO(nduca): Forcing a driver to disable vsync (e.g. in a control panel) is
691 // not caught by this check. This will lead to artificially low frame rates
692 // for people who force vsync off at a driver level and expect Chrome to speed
693 // up.
694 return !has_disable_gpu_vsync_switch_;
695}
696
[email protected]65225772011-05-12 21:10:24697void RenderWidget::InvalidationCallback() {
[email protected]50312bf2011-06-22 23:30:06698 TRACE_EVENT0("renderer", "RenderWidget::InvalidationCallback");
[email protected]65225772011-05-12 21:10:24699 invalidation_task_posted_ = false;
700 DoDeferredUpdateAndSendInputAck();
701}
702
703void RenderWidget::DoDeferredUpdateAndSendInputAck() {
[email protected]52ccd0ea2011-02-16 01:09:05704 DoDeferredUpdate();
705
706 if (pending_input_event_ack_.get())
707 Send(pending_input_event_ack_.release());
[email protected]ee3d3ad2011-02-04 00:42:21708}
709
[email protected]552e6002009-11-19 05:24:57710void RenderWidget::DoDeferredUpdate() {
[email protected]366ae242011-05-10 02:23:58711 TRACE_EVENT0("renderer", "RenderWidget::DoDeferredUpdate");
[email protected]71e2f0a2011-03-15 22:25:08712
[email protected]65225772011-05-12 21:10:24713 if (!webwidget_)
initial.commit09911bf2008-07-26 23:55:29714 return;
[email protected]65225772011-05-12 21:10:24715 if (update_reply_pending()) {
716 TRACE_EVENT0("renderer", "EarlyOut_UpdateReplyPending");
717 return;
718 }
[email protected]9ca84622011-06-02 23:46:39719 if (is_accelerated_compositing_active_ &&
720 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) {
[email protected]65225772011-05-12 21:10:24721 TRACE_EVENT0("renderer", "EarlyOut_MaxSwapBuffersPending");
722 return;
723 }
initial.commit09911bf2008-07-26 23:55:29724
[email protected]552e6002009-11-19 05:24:57725 // Suppress updating when we are hidden.
initial.commit09911bf2008-07-26 23:55:29726 if (is_hidden_ || size_.IsEmpty()) {
[email protected]552e6002009-11-19 05:24:57727 paint_aggregator_.ClearPendingUpdate();
initial.commit09911bf2008-07-26 23:55:29728 needs_repainting_on_restore_ = true;
[email protected]65225772011-05-12 21:10:24729 TRACE_EVENT0("renderer", "EarlyOut_NotVisible");
initial.commit09911bf2008-07-26 23:55:29730 return;
731 }
732
[email protected]0fb93f52011-05-18 23:13:56733 // Tracking of frame rate jitter
734 base::TimeTicks frame_begin_ticks = base::TimeTicks::Now();
[email protected]52ccd0ea2011-02-16 01:09:05735 AnimateIfNeeded();
[email protected]5f8b1022011-01-21 23:34:50736
[email protected]f98d7e3c2010-09-13 22:30:46737 // Layout may generate more invalidation. It may also enable the
738 // GPU acceleration, so make sure to run layout before we send the
739 // GpuRenderingActivated message.
740 webwidget_->layout();
741
[email protected]5f8b1022011-01-21 23:34:50742 // Suppress painting if nothing is dirty. This has to be done after updating
743 // animations running layout as these may generate further invalidations.
[email protected]65225772011-05-12 21:10:24744 if (!paint_aggregator_.HasPendingUpdate()) {
745 TRACE_EVENT0("renderer", "EarlyOut_NoPendingUpdate");
[email protected]5f8b1022011-01-21 23:34:50746 return;
[email protected]65225772011-05-12 21:10:24747 }
[email protected]5f8b1022011-01-21 23:34:50748
[email protected]872ae5b2011-05-26 20:20:50749 if (!last_do_deferred_update_time_.is_null()) {
[email protected]0fb93f52011-05-18 23:13:56750 base::TimeDelta delay = frame_begin_ticks - last_do_deferred_update_time_;
751 if(is_accelerated_compositing_active_)
752 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.AccelDoDeferredUpdateDelay",
753 delay,
754 base::TimeDelta::FromMilliseconds(1),
755 base::TimeDelta::FromMilliseconds(60),
756 30);
757 else
758 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.SoftwareDoDeferredUpdateDelay",
759 delay,
760 base::TimeDelta::FromMilliseconds(1),
761 base::TimeDelta::FromMilliseconds(60),
762 30);
[email protected]872ae5b2011-05-26 20:20:50763
764 // Calculate filtered time per frame:
765 float frame_time_elapsed = static_cast<float>(delay.InSecondsF());
766 filtered_time_per_frame_ =
767 0.9f * filtered_time_per_frame_ + 0.1f * frame_time_elapsed;
[email protected]0fb93f52011-05-18 23:13:56768 }
769 last_do_deferred_update_time_ = frame_begin_ticks;
770
[email protected]552e6002009-11-19 05:24:57771 // OK, save the pending update to a local since painting may cause more
initial.commit09911bf2008-07-26 23:55:29772 // invalidation. Some WebCore rendering objects only layout when painted.
[email protected]dd015812010-12-06 23:39:30773 PaintAggregator::PendingUpdate update;
774 paint_aggregator_.PopPendingUpdate(&update);
initial.commit09911bf2008-07-26 23:55:29775
[email protected]53d3f302009-12-21 04:42:05776 gfx::Rect scroll_damage = update.GetScrollDamage();
777 gfx::Rect bounds = update.GetPaintBounds().Union(scroll_damage);
initial.commit09911bf2008-07-26 23:55:29778
[email protected]27543452011-03-25 00:14:00779 // Compositing the page may disable accelerated compositing.
780 bool accelerated_compositing_was_active = is_accelerated_compositing_active_;
781
[email protected]ca4847f2010-09-24 05:39:15782 // A plugin may be able to do an optimized paint. First check this, in which
783 // case we can skip all of the bitmap generation and regular paint code.
[email protected]719b36f2010-12-22 20:36:46784 // This optimization allows PPAPI plugins that declare themselves on top of
785 // the page (like a traditional windowed plugin) to be able to animate (think
786 // movie playing) without repeatedly re-painting the page underneath, or
787 // copying the plugin backing store (since we can send the plugin's backing
788 // store directly to the browser).
789 //
790 // This optimization only works when the entire invalid region is contained
791 // within the plugin. There is a related optimization in PaintRect for the
792 // case where there may be multiple invalid regions.
[email protected]2650bd52011-03-25 00:34:44793 TransportDIB::Id dib_id = TransportDIB::Id();
[email protected]ca4847f2010-09-24 05:39:15794 TransportDIB* dib = NULL;
[email protected]cef3362f2009-12-21 17:48:45795 std::vector<gfx::Rect> copy_rects;
[email protected]ca4847f2010-09-24 05:39:15796 gfx::Rect optimized_copy_rect, optimized_copy_location;
797 if (update.scroll_rect.IsEmpty() &&
[email protected]a79d8a632010-11-18 22:35:56798 !is_accelerated_compositing_active_ &&
[email protected]ca4847f2010-09-24 05:39:15799 GetBitmapForOptimizedPluginPaint(bounds, &dib, &optimized_copy_location,
800 &optimized_copy_rect)) {
[email protected]2df1b362011-01-21 21:22:27801 // Only update the part of the plugin that actually changed.
802 optimized_copy_rect = optimized_copy_rect.Intersect(bounds);
[email protected]ca4847f2010-09-24 05:39:15803 bounds = optimized_copy_location;
804 copy_rects.push_back(optimized_copy_rect);
805 dib_id = dib->id();
[email protected]a79d8a632010-11-18 22:35:56806 } else if (!is_accelerated_compositing_active_) {
[email protected]f98d7e3c2010-09-13 22:30:46807 // Compute a buffer for painting and cache it.
[email protected]ca4847f2010-09-24 05:39:15808 scoped_ptr<skia::PlatformCanvas> canvas(
[email protected]b4d08452010-10-05 17:34:35809 RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_,
810 bounds));
[email protected]f98d7e3c2010-09-13 22:30:46811 if (!canvas.get()) {
812 NOTREACHED();
813 return;
814 }
[email protected]cef3362f2009-12-21 17:48:45815
[email protected]f98d7e3c2010-09-13 22:30:46816 // We may get back a smaller canvas than we asked for.
817 // TODO(darin): This seems like it could cause painting problems!
818 DCHECK_EQ(bounds.width(), canvas->getDevice()->width());
819 DCHECK_EQ(bounds.height(), canvas->getDevice()->height());
820 bounds.set_width(canvas->getDevice()->width());
821 bounds.set_height(canvas->getDevice()->height());
[email protected]53d3f302009-12-21 04:42:05822
[email protected]f98d7e3c2010-09-13 22:30:46823 HISTOGRAM_COUNTS_100("MPArch.RW_PaintRectCount", update.paint_rects.size());
824
[email protected]f98d7e3c2010-09-13 22:30:46825 // The scroll damage is just another rectangle to paint and copy.
826 copy_rects.swap(update.paint_rects);
827 if (!scroll_damage.IsEmpty())
828 copy_rects.push_back(scroll_damage);
829
830 for (size_t i = 0; i < copy_rects.size(); ++i)
831 PaintRect(copy_rects[i], bounds.origin(), canvas.get());
[email protected]ca4847f2010-09-24 05:39:15832
[email protected]b4d08452010-10-05 17:34:35833 dib_id = current_paint_buf_->id();
[email protected]f98d7e3c2010-09-13 22:30:46834 } else { // Accelerated compositing path
835 // Begin painting.
[email protected]50bd6452010-11-27 19:39:42836 webwidget_->composite(false);
[email protected]f98d7e3c2010-09-13 22:30:46837 }
838
839 // sending an ack to browser process that the paint is complete...
[email protected]53d3f302009-12-21 04:42:05840 ViewHostMsg_UpdateRect_Params params;
[email protected]36808ad2010-10-20 19:18:30841 params.bitmap = dib_id;
[email protected]53d3f302009-12-21 04:42:05842 params.bitmap_rect = bounds;
843 params.dx = update.scroll_delta.x();
844 params.dy = update.scroll_delta.y();
[email protected]27543452011-03-25 00:14:00845 if (accelerated_compositing_was_active) {
[email protected]b167ca662010-05-14 00:05:34846 // If painting is done via the gpu process then we clear out all damage
847 // rects to save the browser process from doing unecessary work.
848 params.scroll_rect = gfx::Rect();
849 params.copy_rects.clear();
850 } else {
851 params.scroll_rect = update.scroll_rect;
852 params.copy_rects.swap(copy_rects); // TODO(darin): clip to bounds?
853 }
[email protected]53d3f302009-12-21 04:42:05854 params.view_size = size_;
[email protected]e2356242010-11-16 22:33:03855 params.resizer_rect = resizer_rect_;
[email protected]53d3f302009-12-21 04:42:05856 params.plugin_window_moves.swap(plugin_window_moves_);
857 params.flags = next_paint_flags_;
[email protected]d54169e92011-01-21 09:19:52858 params.scroll_offset = GetScrollOffset();
[email protected]53d3f302009-12-21 04:42:05859
860 update_reply_pending_ = true;
861 Send(new ViewHostMsg_UpdateRect(routing_id_, params));
862 next_paint_flags_ = 0;
863
[email protected]e99ef6f2011-10-16 01:13:00864 UpdateTextInputState();
865 UpdateSelectionBounds();
[email protected]00c39612010-03-06 02:53:28866
867 // Let derived classes know we've painted.
868 DidInitiatePaint();
initial.commit09911bf2008-07-26 23:55:29869}
870
871///////////////////////////////////////////////////////////////////////////////
[email protected]f98d7e3c2010-09-13 22:30:46872// WebWidgetClient
initial.commit09911bf2008-07-26 23:55:29873
[email protected]4873c7d2009-07-16 06:36:28874void RenderWidget::didInvalidateRect(const WebRect& rect) {
[email protected]552e6002009-11-19 05:24:57875 // The invalidated rect might be outside the bounds of the view.
[email protected]ee8d6fd2010-05-26 17:05:48876 gfx::Rect view_rect(size_);
[email protected]552e6002009-11-19 05:24:57877 gfx::Rect damaged_rect = view_rect.Intersect(rect);
878 if (damaged_rect.IsEmpty())
initial.commit09911bf2008-07-26 23:55:29879 return;
880
[email protected]552e6002009-11-19 05:24:57881 paint_aggregator_.InvalidateRect(damaged_rect);
882
883 // We may not need to schedule another call to DoDeferredUpdate.
[email protected]65225772011-05-12 21:10:24884 if (invalidation_task_posted_)
[email protected]552e6002009-11-19 05:24:57885 return;
886 if (!paint_aggregator_.HasPendingUpdate())
887 return;
[email protected]65225772011-05-12 21:10:24888 if (update_reply_pending() ||
889 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending)
890 return;
891
892 // When GPU rendering, combine pending animations and invalidations into
893 // a single update.
894 if (is_accelerated_compositing_active_ && animation_task_posted_)
[email protected]552e6002009-11-19 05:24:57895 return;
896
897 // Perform updating asynchronously. This serves two purposes:
initial.commit09911bf2008-07-26 23:55:29898 // 1) Ensures that we call WebView::Paint without a bunch of other junk
899 // on the call stack.
900 // 2) Allows us to collect more damage rects before painting to help coalesce
901 // the work that we will need to do.
[email protected]65225772011-05-12 21:10:24902 invalidation_task_posted_ = true;
[email protected]32876ae2011-11-15 22:25:21903 MessageLoop::current()->PostTask(
904 FROM_HERE, base::Bind(&RenderWidget::InvalidationCallback, this));
initial.commit09911bf2008-07-26 23:55:29905}
906
[email protected]4873c7d2009-07-16 06:36:28907void RenderWidget::didScrollRect(int dx, int dy, const WebRect& clip_rect) {
[email protected]f98d7e3c2010-09-13 22:30:46908 // Drop scrolls on the floor when we are in compositing mode.
909 // TODO(nduca): stop WebViewImpl from sending scrolls in the first place.
[email protected]a79d8a632010-11-18 22:35:56910 if (is_accelerated_compositing_active_)
[email protected]f98d7e3c2010-09-13 22:30:46911 return;
912
[email protected]552e6002009-11-19 05:24:57913 // The scrolled rect might be outside the bounds of the view.
[email protected]ee8d6fd2010-05-26 17:05:48914 gfx::Rect view_rect(size_);
[email protected]552e6002009-11-19 05:24:57915 gfx::Rect damaged_rect = view_rect.Intersect(clip_rect);
916 if (damaged_rect.IsEmpty())
initial.commit09911bf2008-07-26 23:55:29917 return;
918
[email protected]552e6002009-11-19 05:24:57919 paint_aggregator_.ScrollRect(dx, dy, damaged_rect);
920
921 // We may not need to schedule another call to DoDeferredUpdate.
[email protected]65225772011-05-12 21:10:24922 if (invalidation_task_posted_)
[email protected]552e6002009-11-19 05:24:57923 return;
924 if (!paint_aggregator_.HasPendingUpdate())
925 return;
[email protected]65225772011-05-12 21:10:24926 if (update_reply_pending() ||
927 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending)
928 return;
929
930 // When GPU rendering, combine pending animations and invalidations into
931 // a single update.
932 if (is_accelerated_compositing_active_ && animation_task_posted_)
[email protected]552e6002009-11-19 05:24:57933 return;
934
935 // Perform updating asynchronously. This serves two purposes:
936 // 1) Ensures that we call WebView::Paint without a bunch of other junk
937 // on the call stack.
938 // 2) Allows us to collect more damage rects before painting to help coalesce
939 // the work that we will need to do.
[email protected]65225772011-05-12 21:10:24940 invalidation_task_posted_ = true;
[email protected]32876ae2011-11-15 22:25:21941 MessageLoop::current()->PostTask(
942 FROM_HERE, base::Bind(&RenderWidget::InvalidationCallback, this));
initial.commit09911bf2008-07-26 23:55:29943}
944
[email protected]3da12cb2011-10-08 02:25:04945void RenderWidget::didActivateCompositor(int compositor_identifier) {
[email protected]ea162f92011-10-04 23:08:22946 TRACE_EVENT0("gpu", "RenderWidget::didActivateCompositor");
947
[email protected]f3150172011-10-22 02:28:45948 CompositorThread* compositor_thread =
949 RenderThreadImpl::current()->compositor_thread();
950 if (compositor_thread)
951 compositor_thread->AddCompositor(routing_id_, compositor_identifier);
[email protected]3da12cb2011-10-08 02:25:04952
[email protected]ea162f92011-10-04 23:08:22953 is_accelerated_compositing_active_ = true;
[email protected]50bd6452010-11-27 19:39:42954 Send(new ViewHostMsg_DidActivateAcceleratedCompositing(
[email protected]65225772011-05-12 21:10:24955 routing_id_, is_accelerated_compositing_active_));
956
[email protected]c3d45532011-10-07 19:20:40957 // Note: asynchronous swapbuffer support currently only matters if
958 // compositing scheduling happens on the RenderWidget.
[email protected]ea162f92011-10-04 23:08:22959 using_asynchronous_swapbuffers_ = SupportsAsynchronousSwapBuffers();
[email protected]ea162f92011-10-04 23:08:22960}
961
962void RenderWidget::didDeactivateCompositor() {
963 TRACE_EVENT0("gpu", "RenderWidget::didDeactivateCompositor");
964
965 is_accelerated_compositing_active_ = false;
966 Send(new ViewHostMsg_DidActivateAcceleratedCompositing(
967 routing_id_, is_accelerated_compositing_active_));
968
[email protected]ea162f92011-10-04 23:08:22969 if (using_asynchronous_swapbuffers_)
[email protected]65225772011-05-12 21:10:24970 using_asynchronous_swapbuffers_ = false;
[email protected]a79d8a632010-11-18 22:35:56971}
972
[email protected]58264a32011-11-17 23:36:15973void RenderWidget::didCommitAndDrawCompositorFrame() {
974}
975
976void RenderWidget::didCompleteSwapBuffers() {
977 if (update_reply_pending())
978 return;
979
980 if (!next_paint_flags_ && !plugin_window_moves_.size())
981 return;
982
983 ViewHostMsg_UpdateRect_Params params;
984 params.view_size = size_;
985 params.resizer_rect = resizer_rect_;
986 params.plugin_window_moves.swap(plugin_window_moves_);
987 params.flags = next_paint_flags_;
988 params.scroll_offset = GetScrollOffset();
989 update_reply_pending_ = true;
990
991 Send(new ViewHostMsg_UpdateRect(routing_id_, params));
992 next_paint_flags_ = 0;
993}
994
[email protected]f98d7e3c2010-09-13 22:30:46995void RenderWidget::scheduleComposite() {
[email protected]c3d45532011-10-07 19:20:40996 if (WebWidgetHandlesCompositorScheduling())
997 webwidget_->composite(false);
998 else {
999 // TODO(nduca): replace with something a little less hacky. The reason this
1000 // hack is still used is because the Invalidate-DoDeferredUpdate loop
1001 // contains a lot of host-renderer synchronization logic that is still
1002 // important for the accelerated compositing case. The option of simply
1003 // duplicating all that code is less desirable than "faking out" the
1004 // invalidation path using a magical damage rect.
1005 didInvalidateRect(WebRect(0, 0, 1, 1));
1006 }
[email protected]f98d7e3c2010-09-13 22:30:461007}
1008
[email protected]5f8b1022011-01-21 23:34:501009void RenderWidget::scheduleAnimation() {
[email protected]921244e42011-07-20 16:36:301010 TRACE_EVENT0("gpu", "RenderWidget::scheduleAnimation");
[email protected]ee3d3ad2011-02-04 00:42:211011 if (!animation_update_pending_) {
1012 animation_update_pending_ = true;
[email protected]52ccd0ea2011-02-16 01:09:051013 if (!animation_task_posted_) {
1014 animation_task_posted_ = true;
[email protected]32876ae2011-11-15 22:25:211015 MessageLoop::current()->PostTask(
1016 FROM_HERE, base::Bind(&RenderWidget::AnimationCallback, this));
[email protected]52ccd0ea2011-02-16 01:09:051017 }
[email protected]ee3d3ad2011-02-04 00:42:211018 }
[email protected]5f8b1022011-01-21 23:34:501019}
1020
[email protected]4873c7d2009-07-16 06:36:281021void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) {
[email protected]7c51b0ee2009-07-08 21:49:301022 // TODO(darin): Eliminate this temporary.
1023 WebCursor cursor(cursor_info);
1024
initial.commit09911bf2008-07-26 23:55:291025 // Only send a SetCursor message if we need to make a change.
1026 if (!current_cursor_.IsEqual(cursor)) {
1027 current_cursor_ = cursor;
1028 Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
1029 }
1030}
1031
1032// We are supposed to get a single call to Show for a newly created RenderWidget
1033// that was created via RenderWidget::CreateWebView. So, we wait until this
1034// point to dispatch the ShowWidget message.
1035//
1036// This method provides us with the information about how to display the newly
[email protected]5f9de5882011-09-30 23:36:281037// created RenderWidget (i.e., as a blocked popup or as a new tab).
initial.commit09911bf2008-07-26 23:55:291038//
[email protected]4873c7d2009-07-16 06:36:281039void RenderWidget::show(WebNavigationPolicy) {
initial.commit09911bf2008-07-26 23:55:291040 DCHECK(!did_show_) << "received extraneous Show call";
1041 DCHECK(routing_id_ != MSG_ROUTING_NONE);
1042 DCHECK(opener_id_ != MSG_ROUTING_NONE);
1043
[email protected]8de12d942010-11-17 20:42:441044 if (did_show_)
1045 return;
1046
1047 did_show_ = true;
1048 // NOTE: initial_pos_ may still have its default values at this point, but
1049 // that's okay. It'll be ignored if as_popup is false, or the browser
1050 // process will impose a default position otherwise.
1051 Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_pos_));
1052 SetPendingWindowRect(initial_pos_);
initial.commit09911bf2008-07-26 23:55:291053}
1054
[email protected]4873c7d2009-07-16 06:36:281055void RenderWidget::didFocus() {
initial.commit09911bf2008-07-26 23:55:291056}
1057
[email protected]4873c7d2009-07-16 06:36:281058void RenderWidget::didBlur() {
initial.commit09911bf2008-07-26 23:55:291059}
1060
[email protected]2533ce12009-05-09 00:02:241061void RenderWidget::DoDeferredClose() {
1062 Send(new ViewHostMsg_Close(routing_id_));
1063}
1064
[email protected]4873c7d2009-07-16 06:36:281065void RenderWidget::closeWidgetSoon() {
initial.commit09911bf2008-07-26 23:55:291066 // If a page calls window.close() twice, we'll end up here twice, but that's
1067 // OK. It is safe to send multiple Close messages.
1068
[email protected]2533ce12009-05-09 00:02:241069 // Ask the RenderWidgetHost to initiate close. We could be called from deep
1070 // in Javascript. If we ask the RendwerWidgetHost to close now, the window
1071 // could be closed before the JS finishes executing. So instead, post a
1072 // message back to the message loop, which won't run until the JS is
1073 // complete, and then the Close message can be sent.
[email protected]32876ae2011-11-15 22:25:211074 MessageLoop::current()->PostTask(
1075 FROM_HERE, base::Bind(&RenderWidget::DoDeferredClose, this));
initial.commit09911bf2008-07-26 23:55:291076}
1077
1078void RenderWidget::Close() {
1079 if (webwidget_) {
[email protected]4873c7d2009-07-16 06:36:281080 webwidget_->close();
initial.commit09911bf2008-07-26 23:55:291081 webwidget_ = NULL;
1082 }
1083}
1084
[email protected]4873c7d2009-07-16 06:36:281085WebRect RenderWidget::windowRect() {
1086 if (pending_window_rect_count_)
1087 return pending_window_rect_;
[email protected]2533ce12009-05-09 00:02:241088
[email protected]b3f2b912009-04-09 16:18:521089 gfx::Rect rect;
1090 Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, &rect));
[email protected]4873c7d2009-07-16 06:36:281091 return rect;
initial.commit09911bf2008-07-26 23:55:291092}
1093
[email protected]8a9d6ca32011-06-06 20:11:301094void RenderWidget::setToolTipText(const WebKit::WebString& text,
1095 WebTextDirection hint) {
[email protected]5a395b72011-08-08 19:13:541096 Send(new ViewHostMsg_SetTooltipText(routing_id_, text, hint));
[email protected]8a9d6ca32011-06-06 20:11:301097}
1098
[email protected]4873c7d2009-07-16 06:36:281099void RenderWidget::setWindowRect(const WebRect& pos) {
initial.commit09911bf2008-07-26 23:55:291100 if (did_show_) {
1101 Send(new ViewHostMsg_RequestMove(routing_id_, pos));
[email protected]2533ce12009-05-09 00:02:241102 SetPendingWindowRect(pos);
initial.commit09911bf2008-07-26 23:55:291103 } else {
1104 initial_pos_ = pos;
1105 }
1106}
1107
[email protected]2533ce12009-05-09 00:02:241108void RenderWidget::SetPendingWindowRect(const WebRect& rect) {
1109 pending_window_rect_ = rect;
1110 pending_window_rect_count_++;
1111}
1112
[email protected]4873c7d2009-07-16 06:36:281113WebRect RenderWidget::rootWindowRect() {
[email protected]2533ce12009-05-09 00:02:241114 if (pending_window_rect_count_) {
1115 // NOTE(mbelshe): If there is a pending_window_rect_, then getting
1116 // the RootWindowRect is probably going to return wrong results since the
1117 // browser may not have processed the Move yet. There isn't really anything
1118 // good to do in this case, and it shouldn't happen - since this size is
1119 // only really needed for windowToScreen, which is only used for Popups.
[email protected]4873c7d2009-07-16 06:36:281120 return pending_window_rect_;
[email protected]2533ce12009-05-09 00:02:241121 }
1122
[email protected]b3f2b912009-04-09 16:18:521123 gfx::Rect rect;
1124 Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, &rect));
[email protected]4873c7d2009-07-16 06:36:281125 return rect;
[email protected]d4547452008-08-28 18:36:371126}
1127
[email protected]4873c7d2009-07-16 06:36:281128WebRect RenderWidget::windowResizerRect() {
1129 return resizer_rect_;
[email protected]c04b6362008-11-21 18:54:191130}
1131
[email protected]fa7b1dc2010-06-23 17:53:041132void RenderWidget::OnSetInputMethodActive(bool is_active) {
[email protected]c4bb35a2008-10-31 17:54:031133 // To prevent this renderer process from sending unnecessary IPC messages to
1134 // a browser process, we permit the renderer process to send IPC messages
[email protected]fa7b1dc2010-06-23 17:53:041135 // only during the input method attached to the browser process is active.
1136 input_method_is_active_ = is_active;
initial.commit09911bf2008-07-26 23:55:291137}
1138
[email protected]fa7b1dc2010-06-23 17:53:041139void RenderWidget::OnImeSetComposition(
1140 const string16& text,
1141 const std::vector<WebCompositionUnderline>& underlines,
1142 int selection_start, int selection_end) {
[email protected]4873c7d2009-07-16 06:36:281143 if (!webwidget_)
1144 return;
[email protected]d4cff272011-05-02 15:46:011145 if (webwidget_->setComposition(
[email protected]fa7b1dc2010-06-23 17:53:041146 text, WebVector<WebCompositionUnderline>(underlines),
1147 selection_start, selection_end)) {
[email protected]d4cff272011-05-02 15:46:011148 // Setting the IME composition was successful. Send the new composition
1149 // range to the browser.
1150 ui::Range range(ui::Range::InvalidRange());
1151 size_t location, length;
1152 if (webwidget_->compositionRange(&location, &length)) {
1153 range.set_start(location);
1154 range.set_end(location + length);
1155 }
1156 // The IME was cancelled via the Esc key, so just send back the caret.
1157 else if (webwidget_->caretOrSelectionRange(&location, &length)) {
1158 range.set_start(location);
1159 range.set_end(location + length);
1160 }
1161 Send(new ViewHostMsg_ImeCompositionRangeChanged(routing_id(), range));
1162 } else {
[email protected]fa7b1dc2010-06-23 17:53:041163 // If we failed to set the composition text, then we need to let the browser
1164 // process to cancel the input method's ongoing composition session, to make
1165 // sure we are in a consistent state.
1166 Send(new ViewHostMsg_ImeCancelComposition(routing_id()));
[email protected]d4cff272011-05-02 15:46:011167
1168 // Send an updated IME range with just the caret range.
1169 ui::Range range(ui::Range::InvalidRange());
1170 size_t location, length;
1171 if (webwidget_->caretOrSelectionRange(&location, &length)) {
1172 range.set_start(location);
1173 range.set_end(location + length);
1174 }
1175 Send(new ViewHostMsg_ImeCompositionRangeChanged(routing_id(), range));
[email protected]7f00efa2010-04-15 05:01:261176 }
[email protected]fa7b1dc2010-06-23 17:53:041177}
1178
[email protected]4de6d1692011-10-12 08:45:441179void RenderWidget::OnImeConfirmComposition(
1180 const string16& text, const ui::Range& replacement_range) {
1181 if (webwidget_) {
[email protected]bb953fd2011-10-31 09:11:571182 handling_input_event_ = true;
[email protected]6b349652011-01-05 18:36:241183 webwidget_->confirmComposition(text);
[email protected]bb953fd2011-10-31 09:11:571184 handling_input_event_ = false;
[email protected]4de6d1692011-10-12 08:45:441185 }
[email protected]d4cff272011-05-02 15:46:011186 // Send an updated IME range with just the caret range.
1187 ui::Range range(ui::Range::InvalidRange());
1188 size_t location, length;
1189 if (webwidget_->caretOrSelectionRange(&location, &length)) {
1190 range.set_start(location);
1191 range.set_end(location + length);
1192 }
1193 Send(new ViewHostMsg_ImeCompositionRangeChanged(routing_id(), range));
initial.commit09911bf2008-07-26 23:55:291194}
1195
[email protected]948f7ab72010-05-28 23:48:081196// This message causes the renderer to render an image of the
1197// desired_size, regardless of whether the tab is hidden or not.
[email protected]d65adb12010-04-28 17:26:491198void RenderWidget::OnMsgPaintAtSize(const TransportDIB::Handle& dib_handle,
[email protected]c88c9442010-07-19 18:55:091199 int tag,
[email protected]948f7ab72010-05-28 23:48:081200 const gfx::Size& page_size,
[email protected]d65adb12010-04-28 17:26:491201 const gfx::Size& desired_size) {
[email protected]27543452011-03-25 00:14:001202 if (!webwidget_ || !TransportDIB::is_valid_handle(dib_handle)) {
1203 if (TransportDIB::is_valid_handle(dib_handle)) {
[email protected]45c6aad32010-11-11 04:46:251204 // Close our unused handle.
1205#if defined(OS_WIN)
1206 ::CloseHandle(dib_handle);
1207#elif defined(OS_MACOSX)
1208 base::SharedMemory::CloseHandle(dib_handle);
1209#endif
1210 }
[email protected]d65adb12010-04-28 17:26:491211 return;
[email protected]45c6aad32010-11-11 04:46:251212 }
[email protected]d65adb12010-04-28 17:26:491213
[email protected]948f7ab72010-05-28 23:48:081214 if (page_size.IsEmpty() || desired_size.IsEmpty()) {
[email protected]d65adb12010-04-28 17:26:491215 // If one of these is empty, then we just return the dib we were
1216 // given, to avoid leaking it.
[email protected]c88c9442010-07-19 18:55:091217 Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, desired_size));
[email protected]d65adb12010-04-28 17:26:491218 return;
1219 }
1220
1221 // Map the given DIB ID into this process, and unmap it at the end
1222 // of this function.
[email protected]45c6aad32010-11-11 04:46:251223 scoped_ptr<TransportDIB> paint_at_size_buffer(
1224 TransportDIB::CreateWithHandle(dib_handle));
[email protected]36808ad2010-10-20 19:18:301225
1226 gfx::Size canvas_size = page_size;
[email protected]d65adb12010-04-28 17:26:491227 float x_scale = static_cast<float>(desired_size.width()) /
1228 static_cast<float>(canvas_size.width());
1229 float y_scale = static_cast<float>(desired_size.height()) /
1230 static_cast<float>(canvas_size.height());
1231
[email protected]ee8d6fd2010-05-26 17:05:481232 gfx::Rect orig_bounds(canvas_size);
[email protected]d65adb12010-04-28 17:26:491233 canvas_size.set_width(static_cast<int>(canvas_size.width() * x_scale));
1234 canvas_size.set_height(static_cast<int>(canvas_size.height() * y_scale));
[email protected]ee8d6fd2010-05-26 17:05:481235 gfx::Rect bounds(canvas_size);
[email protected]d65adb12010-04-28 17:26:491236
[email protected]36808ad2010-10-20 19:18:301237 scoped_ptr<skia::PlatformCanvas> canvas(
1238 paint_at_size_buffer->GetPlatformCanvas(canvas_size.width(),
1239 canvas_size.height()));
1240 if (!canvas.get()) {
1241 NOTREACHED();
1242 return;
1243 }
1244
[email protected]d65adb12010-04-28 17:26:491245 // Reset bounds to what we actually received, but they should be the
1246 // same.
1247 DCHECK_EQ(bounds.width(), canvas->getDevice()->width());
1248 DCHECK_EQ(bounds.height(), canvas->getDevice()->height());
1249 bounds.set_width(canvas->getDevice()->width());
1250 bounds.set_height(canvas->getDevice()->height());
1251
1252 canvas->save();
[email protected]948f7ab72010-05-28 23:48:081253 // Add the scale factor to the canvas, so that we'll get the desired size.
[email protected]d65adb12010-04-28 17:26:491254 canvas->scale(SkFloatToScalar(x_scale), SkFloatToScalar(y_scale));
1255
[email protected]948f7ab72010-05-28 23:48:081256 // Have to make sure we're laid out at the right size before
1257 // rendering.
1258 gfx::Size old_size = webwidget_->size();
1259 webwidget_->resize(page_size);
1260 webwidget_->layout();
1261
[email protected]d65adb12010-04-28 17:26:491262 // Paint the entire thing (using original bounds, not scaled bounds).
1263 PaintRect(orig_bounds, orig_bounds.origin(), canvas.get());
1264 canvas->restore();
1265
[email protected]948f7ab72010-05-28 23:48:081266 // Return the widget to its previous size.
1267 webwidget_->resize(old_size);
1268
[email protected]c88c9442010-07-19 18:55:091269 Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, bounds.size()));
[email protected]d65adb12010-04-28 17:26:491270}
1271
[email protected]ec7dc112008-08-06 05:30:121272void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) {
1273 // During shutdown we can just ignore this message.
1274 if (!webwidget_)
1275 return;
1276
1277 set_next_paint_is_repaint_ack();
[email protected]a79d8a632010-11-18 22:35:561278 if (is_accelerated_compositing_active_) {
[email protected]f98d7e3c2010-09-13 22:30:461279 scheduleComposite();
1280 } else {
1281 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height());
1282 didInvalidateRect(repaint_rect);
1283 }
[email protected]ec7dc112008-08-06 05:30:121284}
1285
[email protected]4873c7d2009-07-16 06:36:281286void RenderWidget::OnSetTextDirection(WebTextDirection direction) {
[email protected]07f953332009-03-25 04:31:111287 if (!webwidget_)
1288 return;
[email protected]4873c7d2009-07-16 06:36:281289 webwidget_->setTextDirection(direction);
[email protected]07f953332009-03-25 04:31:111290}
1291
[email protected]719b36f2010-12-22 20:36:461292webkit::ppapi::PluginInstance* RenderWidget::GetBitmapForOptimizedPluginPaint(
[email protected]ca4847f2010-09-24 05:39:151293 const gfx::Rect& paint_bounds,
1294 TransportDIB** dib,
1295 gfx::Rect* location,
1296 gfx::Rect* clip) {
[email protected]719b36f2010-12-22 20:36:461297 // Bare RenderWidgets don't support optimized plugin painting.
1298 return NULL;
[email protected]ca4847f2010-09-24 05:39:151299}
1300
[email protected]bcaf2272011-02-15 15:29:431301gfx::Point RenderWidget::GetScrollOffset() {
[email protected]d54169e92011-01-21 09:19:521302 // Bare RenderWidgets don't support scroll offset.
[email protected]bcaf2272011-02-15 15:29:431303 return gfx::Point(0, 0);
[email protected]d54169e92011-01-21 09:19:521304}
1305
[email protected]bee16aab2009-08-26 15:55:031306void RenderWidget::SetHidden(bool hidden) {
1307 if (is_hidden_ == hidden)
1308 return;
1309
1310 // The status has changed. Tell the RenderThread about it.
1311 is_hidden_ = hidden;
1312 if (is_hidden_)
[email protected]380244092011-10-07 17:26:271313 RenderThread::Get()->WidgetHidden();
[email protected]bee16aab2009-08-26 15:55:031314 else
[email protected]380244092011-10-07 17:26:271315 RenderThread::Get()->WidgetRestored();
[email protected]bee16aab2009-08-26 15:55:031316}
1317
[email protected]2b624c562011-10-27 22:58:261318void RenderWidget::WillToggleFullscreen() {
1319#ifdef WEBKIT_HAS_NEW_FULLSCREEN_API
1320 if (!webwidget_)
1321 return;
1322
1323 if (is_fullscreen_) {
1324 webwidget_->willExitFullScreen();
1325 } else {
1326 webwidget_->willEnterFullScreen();
1327 }
1328#endif
1329}
1330
1331void RenderWidget::DidToggleFullscreen() {
1332#ifdef WEBKIT_HAS_NEW_FULLSCREEN_API
1333 if (!webwidget_)
1334 return;
1335
1336 if (is_fullscreen_) {
1337 webwidget_->didEnterFullScreen();
1338 } else {
1339 webwidget_->didExitFullScreen();
1340 }
1341#endif
1342}
1343
[email protected]699ab0d2009-04-23 23:19:141344void RenderWidget::SetBackground(const SkBitmap& background) {
1345 background_ = background;
[email protected]f98d7e3c2010-09-13 22:30:461346
[email protected]699ab0d2009-04-23 23:19:141347 // Generate a full repaint.
[email protected]4873c7d2009-07-16 06:36:281348 didInvalidateRect(gfx::Rect(size_.width(), size_.height()));
[email protected]699ab0d2009-04-23 23:19:141349}
1350
[email protected]674741932009-02-04 23:44:461351bool RenderWidget::next_paint_is_resize_ack() const {
[email protected]53d3f302009-12-21 04:42:051352 return ViewHostMsg_UpdateRect_Flags::is_resize_ack(next_paint_flags_);
[email protected]674741932009-02-04 23:44:461353}
1354
1355bool RenderWidget::next_paint_is_restore_ack() const {
[email protected]53d3f302009-12-21 04:42:051356 return ViewHostMsg_UpdateRect_Flags::is_restore_ack(next_paint_flags_);
[email protected]674741932009-02-04 23:44:461357}
1358
1359void RenderWidget::set_next_paint_is_resize_ack() {
[email protected]53d3f302009-12-21 04:42:051360 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK;
[email protected]674741932009-02-04 23:44:461361}
1362
1363void RenderWidget::set_next_paint_is_restore_ack() {
[email protected]53d3f302009-12-21 04:42:051364 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK;
[email protected]674741932009-02-04 23:44:461365}
1366
1367void RenderWidget::set_next_paint_is_repaint_ack() {
[email protected]53d3f302009-12-21 04:42:051368 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK;
[email protected]674741932009-02-04 23:44:461369}
1370
[email protected]e99ef6f2011-10-16 01:13:001371void RenderWidget::UpdateTextInputState() {
[email protected]fa7b1dc2010-06-23 17:53:041372 if (!input_method_is_active_)
initial.commit09911bf2008-07-26 23:55:291373 return;
[email protected]fa7b1dc2010-06-23 17:53:041374
[email protected]ad26ef42011-06-17 07:59:451375 ui::TextInputType new_type = GetTextInputType();
1376 bool new_can_compose_inline = CanComposeInline();
[email protected]e99ef6f2011-10-16 01:13:001377 // Only sends text input type and compose inline to the browser process if
1378 // they are changed.
1379 if (text_input_type_ != new_type ||
[email protected]ad26ef42011-06-17 07:59:451380 can_compose_inline_ != new_can_compose_inline) {
[email protected]fa7b1dc2010-06-23 17:53:041381 text_input_type_ = new_type;
[email protected]ad26ef42011-06-17 07:59:451382 can_compose_inline_ = new_can_compose_inline;
[email protected]e99ef6f2011-10-16 01:13:001383 Send(new ViewHostMsg_TextInputStateChanged(
1384 routing_id(), new_type, new_can_compose_inline));
initial.commit09911bf2008-07-26 23:55:291385 }
initial.commit09911bf2008-07-26 23:55:291386}
1387
[email protected]3f783362011-10-21 22:40:501388void RenderWidget::GetSelectionBounds(gfx::Rect* start, gfx::Rect* end) {
1389 WebRect start_webrect;
1390 WebRect end_webrect;
1391 webwidget_->selectionBounds(start_webrect, end_webrect);
1392 *start = start_webrect;
1393 *end = end_webrect;
[email protected]73bf95812011-10-12 11:38:321394}
1395
[email protected]e99ef6f2011-10-16 01:13:001396void RenderWidget::UpdateSelectionBounds() {
1397 if (!webwidget_)
1398 return;
1399
[email protected]3f783362011-10-21 22:40:501400 gfx::Rect start_rect;
1401 gfx::Rect end_rect;
1402 GetSelectionBounds(&start_rect, &end_rect);
[email protected]e99ef6f2011-10-16 01:13:001403 if (selection_start_rect_ == start_rect && selection_end_rect_ == end_rect)
1404 return;
1405
1406 selection_start_rect_ = start_rect;
1407 selection_end_rect_ = end_rect;
1408 Send(new ViewHostMsg_SelectionBoundsChanged(
1409 routing_id_, selection_start_rect_, selection_end_rect_));
1410}
1411
[email protected]73bf95812011-10-12 11:38:321412// Check WebKit::WebTextInputType and ui::TextInputType is kept in sync.
[email protected]ad26ef42011-06-17 07:59:451413COMPILE_ASSERT(int(WebKit::WebTextInputTypeNone) == \
1414 int(ui::TEXT_INPUT_TYPE_NONE), mismatching_enums);
1415COMPILE_ASSERT(int(WebKit::WebTextInputTypeText) == \
1416 int(ui::TEXT_INPUT_TYPE_TEXT), mismatching_enums);
1417COMPILE_ASSERT(int(WebKit::WebTextInputTypePassword) == \
1418 int(ui::TEXT_INPUT_TYPE_PASSWORD), mismatching_enums);
[email protected]caf38ed2011-07-28 13:15:181419COMPILE_ASSERT(int(WebKit::WebTextInputTypeSearch) == \
1420 int(ui::TEXT_INPUT_TYPE_SEARCH), mismatching_enums);
1421COMPILE_ASSERT(int(WebKit::WebTextInputTypeEmail) == \
1422 int(ui::TEXT_INPUT_TYPE_EMAIL), mismatching_enums);
1423COMPILE_ASSERT(int(WebKit::WebTextInputTypeNumber) == \
1424 int(ui::TEXT_INPUT_TYPE_NUMBER), mismatching_enums);
1425COMPILE_ASSERT(int(WebKit::WebTextInputTypeTelephone) == \
1426 int(ui::TEXT_INPUT_TYPE_TELEPHONE), mismatching_enums);
1427COMPILE_ASSERT(int(WebKit::WebTextInputTypeURL) == \
1428 int(ui::TEXT_INPUT_TYPE_URL), mismatching_enums);
[email protected]ad26ef42011-06-17 07:59:451429
1430ui::TextInputType RenderWidget::GetTextInputType() {
1431 if (webwidget_) {
1432 int type = webwidget_->textInputType();
1433 // Check the type is in the range representable by ui::TextInputType.
[email protected]caf38ed2011-07-28 13:15:181434 DCHECK(type <= ui::TEXT_INPUT_TYPE_URL) <<
[email protected]ad26ef42011-06-17 07:59:451435 "WebKit::WebTextInputType and ui::TextInputType not synchronized";
1436 return static_cast<ui::TextInputType>(type);
1437 }
1438 return ui::TEXT_INPUT_TYPE_NONE;
1439}
1440
1441bool RenderWidget::CanComposeInline() {
1442 return true;
[email protected]56ea1a62011-05-30 07:05:571443}
1444
[email protected]4873c7d2009-07-16 06:36:281445WebScreenInfo RenderWidget::screenInfo() {
1446 WebScreenInfo results;
1447 Send(new ViewHostMsg_GetScreenInfo(routing_id_, host_window_, &results));
1448 return results;
1449}
1450
[email protected]fa7b1dc2010-06-23 17:53:041451void RenderWidget::resetInputMethod() {
1452 if (!input_method_is_active_)
1453 return;
1454
1455 // If the last text input type is not None, then we should finish any
1456 // ongoing composition regardless of the new text input type.
[email protected]ad26ef42011-06-17 07:59:451457 if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE) {
[email protected]fa7b1dc2010-06-23 17:53:041458 // If a composition text exists, then we need to let the browser process
1459 // to cancel the input method's ongoing composition session.
1460 if (webwidget_->confirmComposition())
1461 Send(new ViewHostMsg_ImeCancelComposition(routing_id()));
1462 }
[email protected]d4cff272011-05-02 15:46:011463
1464 // Send an updated IME range with the current caret rect.
1465 ui::Range range(ui::Range::InvalidRange());
1466 size_t location, length;
1467 if (webwidget_->caretOrSelectionRange(&location, &length)) {
1468 range.set_start(location);
1469 range.set_end(location + length);
1470 }
1471 Send(new ViewHostMsg_ImeCompositionRangeChanged(routing_id(), range));
[email protected]fa7b1dc2010-06-23 17:53:041472}
1473
[email protected]f103ab72009-09-02 17:10:591474void RenderWidget::SchedulePluginMove(
[email protected]191eb3f72010-12-21 06:27:501475 const webkit::npapi::WebPluginGeometry& move) {
initial.commit09911bf2008-07-26 23:55:291476 size_t i = 0;
1477 for (; i < plugin_window_moves_.size(); ++i) {
1478 if (plugin_window_moves_[i].window == move.window) {
[email protected]16f89d02009-08-26 17:17:581479 if (move.rects_valid) {
1480 plugin_window_moves_[i] = move;
1481 } else {
1482 plugin_window_moves_[i].visible = move.visible;
1483 }
initial.commit09911bf2008-07-26 23:55:291484 break;
1485 }
1486 }
1487
1488 if (i == plugin_window_moves_.size())
1489 plugin_window_moves_.push_back(move);
1490}
[email protected]268654772009-08-06 23:02:041491
1492void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) {
1493 for (WebPluginGeometryVector::iterator i = plugin_window_moves_.begin();
1494 i != plugin_window_moves_.end(); ++i) {
1495 if (i->window == window) {
1496 plugin_window_moves_.erase(i);
1497 break;
1498 }
1499 }
1500}
[email protected]67bfb83f2011-09-22 03:36:371501
1502bool RenderWidget::WillHandleMouseEvent(const WebKit::WebMouseEvent& event) {
1503 return false;
1504}
[email protected]c3d45532011-10-07 19:20:401505
1506bool RenderWidget::WebWidgetHandlesCompositorScheduling() const {
1507 return false;
1508}