blob: 863e73dfcaa559aa9009a335d97c02fa53a1f2bf [file] [log] [blame]
[email protected]05d478752009-04-08 23:38:161// Copyright (c) 2009 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
5#include "chrome/renderer/render_widget.h"
6
initial.commit09911bf2008-07-26 23:55:297#include "base/gfx/point.h"
8#include "base/gfx/size.h"
9#include "base/logging.h"
10#include "base/message_loop.h"
initial.commit09911bf2008-07-26 23:55:2911#include "base/scoped_ptr.h"
[email protected]661eb9d2009-02-03 02:11:4812#include "build/build_config.h"
[email protected]674741932009-02-04 23:44:4613#include "chrome/common/render_messages.h"
[email protected]e68e62fa2009-02-20 02:00:0414#include "chrome/common/transport_dib.h"
[email protected]8085dbc82008-09-26 22:53:4415#include "chrome/renderer/render_process.h"
[email protected]661eb9d2009-02-03 02:11:4816#include "skia/ext/platform_canvas.h"
[email protected]d5282e72009-05-13 13:16:5217#include "third_party/skia/include/core/SkShader.h"
[email protected]7c51b0ee2009-07-08 21:49:3018#include "webkit/api/public/WebCursorInfo.h"
[email protected]4873c7d2009-07-16 06:36:2819#include "webkit/api/public/WebPopupMenu.h"
[email protected]88efb7ec2009-07-14 16:32:5920#include "webkit/api/public/WebPopupMenuInfo.h"
[email protected]afdcf5c2009-05-10 20:30:4121#include "webkit/api/public/WebRect.h"
22#include "webkit/api/public/WebScreenInfo.h"
23#include "webkit/api/public/WebSize.h"
[email protected]8c89e7792009-08-19 21:18:3424#include "webkit/glue/webkit_glue.h"
[email protected]661eb9d2009-02-03 02:11:4825
26#if defined(OS_POSIX)
[email protected]d5282e72009-05-13 13:16:5227#include "third_party/skia/include/core/SkPixelRef.h"
28#include "third_party/skia/include/core/SkMallocPixelRef.h"
[email protected]661eb9d2009-02-03 02:11:4829#endif // defined(OS_POSIX)
[email protected]8085dbc82008-09-26 22:53:4430
[email protected]4873c7d2009-07-16 06:36:2831#include "webkit/api/public/WebWidget.h"
initial.commit09911bf2008-07-26 23:55:2932
[email protected]4873c7d2009-07-16 06:36:2833using WebKit::WebCompositionCommand;
[email protected]7c51b0ee2009-07-08 21:49:3034using WebKit::WebCursorInfo;
[email protected]62cb33cae2009-03-27 23:30:2235using WebKit::WebInputEvent;
[email protected]4873c7d2009-07-16 06:36:2836using WebKit::WebNavigationPolicy;
37using WebKit::WebPopupMenu;
[email protected]88efb7ec2009-07-14 16:32:5938using WebKit::WebPopupMenuInfo;
[email protected]b3f2b912009-04-09 16:18:5239using WebKit::WebRect;
[email protected]12456fa2009-04-01 23:07:1940using WebKit::WebScreenInfo;
[email protected]b3f2b912009-04-09 16:18:5241using WebKit::WebSize;
[email protected]4873c7d2009-07-16 06:36:2842using WebKit::WebTextDirection;
[email protected]62cb33cae2009-03-27 23:30:2243
[email protected]cfd727f2009-01-09 20:21:1144RenderWidget::RenderWidget(RenderThreadBase* render_thread, bool activatable)
initial.commit09911bf2008-07-26 23:55:2945 : routing_id_(MSG_ROUTING_NONE),
[email protected]c5b3b5e2009-02-13 06:41:1146 webwidget_(NULL),
initial.commit09911bf2008-07-26 23:55:2947 opener_id_(MSG_ROUTING_NONE),
[email protected]8085dbc82008-09-26 22:53:4448 render_thread_(render_thread),
initial.commit09911bf2008-07-26 23:55:2949 host_window_(NULL),
50 current_paint_buf_(NULL),
51 current_scroll_buf_(NULL),
52 next_paint_flags_(0),
53 paint_reply_pending_(false),
54 did_show_(false),
initial.commit09911bf2008-07-26 23:55:2955 is_hidden_(false),
56 needs_repainting_on_restore_(false),
57 has_focus_(false),
[email protected]5dd768212009-08-13 23:34:4958 handling_input_event_(false),
[email protected]661eb9d2009-02-03 02:11:4859 closing_(false),
initial.commit09911bf2008-07-26 23:55:2960 ime_is_active_(false),
61 ime_control_enable_ime_(true),
62 ime_control_x_(-1),
63 ime_control_y_(-1),
64 ime_control_new_state_(false),
[email protected]0ebf3872008-11-07 21:35:0365 ime_control_updated_(false),
[email protected]9f23f592008-11-17 08:36:3466 ime_control_busy_(false),
[email protected]2533ce12009-05-09 00:02:2467 activatable_(activatable),
68 pending_window_rect_count_(0) {
[email protected]8930d472009-02-21 08:05:2869 RenderProcess::current()->AddRefProcess();
[email protected]8085dbc82008-09-26 22:53:4470 DCHECK(render_thread_);
initial.commit09911bf2008-07-26 23:55:2971}
72
73RenderWidget::~RenderWidget() {
[email protected]c5b3b5e2009-02-13 06:41:1174 DCHECK(!webwidget_) << "Leaking our WebWidget!";
initial.commit09911bf2008-07-26 23:55:2975 if (current_paint_buf_) {
[email protected]8930d472009-02-21 08:05:2876 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
initial.commit09911bf2008-07-26 23:55:2977 current_paint_buf_ = NULL;
78 }
79 if (current_scroll_buf_) {
[email protected]8930d472009-02-21 08:05:2880 RenderProcess::current()->ReleaseTransportDIB(current_scroll_buf_);
initial.commit09911bf2008-07-26 23:55:2981 current_scroll_buf_ = NULL;
82 }
[email protected]8930d472009-02-21 08:05:2883 RenderProcess::current()->ReleaseProcess();
initial.commit09911bf2008-07-26 23:55:2984}
85
86/*static*/
[email protected]8085dbc82008-09-26 22:53:4487RenderWidget* RenderWidget::Create(int32 opener_id,
[email protected]0ebf3872008-11-07 21:35:0388 RenderThreadBase* render_thread,
[email protected]cfd727f2009-01-09 20:21:1189 bool activatable) {
initial.commit09911bf2008-07-26 23:55:2990 DCHECK(opener_id != MSG_ROUTING_NONE);
[email protected]0ebf3872008-11-07 21:35:0391 scoped_refptr<RenderWidget> widget = new RenderWidget(render_thread,
[email protected]cfd727f2009-01-09 20:21:1192 activatable);
initial.commit09911bf2008-07-26 23:55:2993 widget->Init(opener_id); // adds reference
94 return widget;
95}
96
[email protected]88efb7ec2009-07-14 16:32:5997void RenderWidget::ConfigureAsExternalPopupMenu(const WebPopupMenuInfo& info) {
98 popup_params_.reset(new ViewHostMsg_ShowPopup_Params);
99 popup_params_->item_height = info.itemHeight;
100 popup_params_->selected_item = info.selectedIndex;
101 for (size_t i = 0; i < info.items.size(); ++i)
102 popup_params_->popup_items.push_back(WebMenuItem(info.items[i]));
103}
104
initial.commit09911bf2008-07-26 23:55:29105void RenderWidget::Init(int32 opener_id) {
106 DCHECK(!webwidget_);
107
108 if (opener_id != MSG_ROUTING_NONE)
109 opener_id_ = opener_id;
110
[email protected]4873c7d2009-07-16 06:36:28111 webwidget_ = WebPopupMenu::create(this);
initial.commit09911bf2008-07-26 23:55:29112
[email protected]8085dbc82008-09-26 22:53:44113 bool result = render_thread_->Send(
[email protected]cfd727f2009-01-09 20:21:11114 new ViewHostMsg_CreateWidget(opener_id, activatable_, &routing_id_));
initial.commit09911bf2008-07-26 23:55:29115 if (result) {
[email protected]8085dbc82008-09-26 22:53:44116 render_thread_->AddRoute(routing_id_, this);
initial.commit09911bf2008-07-26 23:55:29117 // Take a reference on behalf of the RenderThread. This will be balanced
118 // when we receive ViewMsg_Close.
119 AddRef();
120 } else {
121 DCHECK(false);
122 }
123}
124
125// This is used to complete pending inits and non-pending inits. For non-
126// pending cases, the parent will be the same as the current parent. This
127// indicates we do not need to reparent or anything.
[email protected]18bcc3c2009-01-27 21:39:15128void RenderWidget::CompleteInit(gfx::NativeViewId parent_hwnd) {
initial.commit09911bf2008-07-26 23:55:29129 DCHECK(routing_id_ != MSG_ROUTING_NONE);
initial.commit09911bf2008-07-26 23:55:29130
131 host_window_ = parent_hwnd;
132
[email protected]6de74452009-02-25 18:04:59133 Send(new ViewHostMsg_RenderViewReady(routing_id_));
initial.commit09911bf2008-07-26 23:55:29134}
135
136IPC_DEFINE_MESSAGE_MAP(RenderWidget)
137 IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
138 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
139 IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize)
140 IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden)
141 IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored)
142 IPC_MESSAGE_HANDLER(ViewMsg_PaintRect_ACK, OnPaintRectAck)
143 IPC_MESSAGE_HANDLER(ViewMsg_ScrollRect_ACK, OnScrollRectAck)
144 IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent)
145 IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost)
146 IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus)
147 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetInputMode, OnImeSetInputMode)
148 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition)
[email protected]ec7dc112008-08-06 05:30:12149 IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint)
[email protected]07f953332009-03-25 04:31:11150 IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection)
[email protected]2533ce12009-05-09 00:02:24151 IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck)
initial.commit09911bf2008-07-26 23:55:29152 IPC_MESSAGE_UNHANDLED_ERROR()
153IPC_END_MESSAGE_MAP()
154
155bool RenderWidget::Send(IPC::Message* message) {
156 // Don't send any messages after the browser has told us to close.
157 if (closing_) {
158 delete message;
159 return false;
160 }
161
162 // If given a messsage without a routing ID, then assign our routing ID.
163 if (message->routing_id() == MSG_ROUTING_NONE)
164 message->set_routing_id(routing_id_);
165
[email protected]d3fc25652009-02-24 22:31:25166 return render_thread_->Send(message);
[email protected]8085dbc82008-09-26 22:53:44167}
168
initial.commit09911bf2008-07-26 23:55:29169// Got a response from the browser after the renderer decided to create a new
170// view.
[email protected]18bcc3c2009-01-27 21:39:15171void RenderWidget::OnCreatingNewAck(gfx::NativeViewId parent) {
initial.commit09911bf2008-07-26 23:55:29172 DCHECK(routing_id_ != MSG_ROUTING_NONE);
173
174 CompleteInit(parent);
175}
176
177void RenderWidget::OnClose() {
178 if (closing_)
179 return;
180 closing_ = true;
181
182 // Browser correspondence is no longer needed at this point.
183 if (routing_id_ != MSG_ROUTING_NONE)
[email protected]8085dbc82008-09-26 22:53:44184 render_thread_->RemoveRoute(routing_id_);
initial.commit09911bf2008-07-26 23:55:29185
initial.commit09911bf2008-07-26 23:55:29186 // If there is a Send call on the stack, then it could be dangerous to close
[email protected]d3fc25652009-02-24 22:31:25187 // now. Post a task that only gets invoked when there are no nested message
188 // loops.
189 MessageLoop::current()->PostNonNestableTask(FROM_HERE,
190 NewRunnableMethod(this, &RenderWidget::Close));
191
192 // Balances the AddRef taken when we called AddRoute.
193 Release();
initial.commit09911bf2008-07-26 23:55:29194}
195
[email protected]f21c613a2009-02-12 14:46:17196void RenderWidget::OnResize(const gfx::Size& new_size,
197 const gfx::Rect& resizer_rect) {
initial.commit09911bf2008-07-26 23:55:29198 // During shutdown we can just ignore this message.
199 if (!webwidget_)
200 return;
201
[email protected]f21c613a2009-02-12 14:46:17202 // Remember the rect where the resize corner will be drawn.
203 resizer_rect_ = resizer_rect;
204
initial.commit09911bf2008-07-26 23:55:29205 // TODO(darin): We should not need to reset this here.
206 is_hidden_ = false;
207 needs_repainting_on_restore_ = false;
208
209 // We shouldn't be asked to resize to our current size.
210 DCHECK(size_ != new_size);
211 size_ = new_size;
212
213 // We should not be sent a Resize message if we have not ACK'd the previous
214 DCHECK(!next_paint_is_resize_ack());
215
216 // When resizing, we want to wait to paint before ACK'ing the resize. This
217 // ensures that we only resize as fast as we can paint. We only need to send
218 // an ACK if we are resized to a non-empty rect.
[email protected]4873c7d2009-07-16 06:36:28219 webwidget_->resize(new_size);
initial.commit09911bf2008-07-26 23:55:29220 if (!new_size.IsEmpty()) {
[email protected]2d5d09d52009-06-15 14:29:21221 DCHECK(!paint_rect_.IsEmpty());
initial.commit09911bf2008-07-26 23:55:29222
223 // This should have caused an invalidation of the entire view. The damaged
224 // rect could be larger than new_size if we are being made smaller.
[email protected]2d5d09d52009-06-15 14:29:21225 DCHECK_GE(paint_rect_.width(), new_size.width());
226 DCHECK_GE(paint_rect_.height(), new_size.height());
227
initial.commit09911bf2008-07-26 23:55:29228 // We will send the Resize_ACK flag once we paint again.
229 set_next_paint_is_resize_ack();
230 }
231}
232
233void RenderWidget::OnWasHidden() {
234 // Go into a mode where we stop generating paint and scrolling events.
235 is_hidden_ = true;
236}
237
238void RenderWidget::OnWasRestored(bool needs_repainting) {
239 // During shutdown we can just ignore this message.
240 if (!webwidget_)
241 return;
242
243 // See OnWasHidden
244 is_hidden_ = false;
245
246 if (!needs_repainting && !needs_repainting_on_restore_)
247 return;
248 needs_repainting_on_restore_ = false;
249
250 // Tag the next paint as a restore ack, which is picked up by DoDeferredPaint
251 // when it sends out the next PaintRect message.
252 set_next_paint_is_restore_ack();
253
254 // Generate a full repaint.
[email protected]4873c7d2009-07-16 06:36:28255 didInvalidateRect(gfx::Rect(size_.width(), size_.height()));
initial.commit09911bf2008-07-26 23:55:29256}
257
[email protected]b7fce1f2008-08-14 05:01:07258void RenderWidget::OnPaintRectAck() {
initial.commit09911bf2008-07-26 23:55:29259 DCHECK(paint_reply_pending());
260 paint_reply_pending_ = false;
[email protected]b7fce1f2008-08-14 05:01:07261 // If we sent a PaintRect message with a zero-sized bitmap, then
262 // we should have no current paint buf.
263 if (current_paint_buf_) {
[email protected]8930d472009-02-21 08:05:28264 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
[email protected]b7fce1f2008-08-14 05:01:07265 current_paint_buf_ = NULL;
initial.commit09911bf2008-07-26 23:55:29266 }
[email protected]e68e62fa2009-02-20 02:00:04267
[email protected]a2f6bc112009-06-27 16:27:25268 // Notify subclasses
269 DidPaint();
270
initial.commit09911bf2008-07-26 23:55:29271 // Continue painting if necessary...
272 DoDeferredPaint();
273}
274
[email protected]2533ce12009-05-09 00:02:24275void RenderWidget::OnRequestMoveAck() {
276 DCHECK(pending_window_rect_count_);
277 pending_window_rect_count_--;
278}
279
initial.commit09911bf2008-07-26 23:55:29280void RenderWidget::OnScrollRectAck() {
281 DCHECK(scroll_reply_pending());
282
[email protected]e68e62fa2009-02-20 02:00:04283 if (current_scroll_buf_) {
[email protected]8930d472009-02-21 08:05:28284 RenderProcess::current()->ReleaseTransportDIB(current_scroll_buf_);
[email protected]e68e62fa2009-02-20 02:00:04285 current_scroll_buf_ = NULL;
286 }
initial.commit09911bf2008-07-26 23:55:29287
288 // Continue scrolling if necessary...
289 DoDeferredScroll();
290}
291
292void RenderWidget::OnHandleInputEvent(const IPC::Message& message) {
293 void* iter = NULL;
294
295 const char* data;
296 int data_length;
[email protected]5dd768212009-08-13 23:34:49297 handling_input_event_ = true;
298 if (!message.ReadData(&iter, &data, &data_length)) {
299 handling_input_event_ = false;
initial.commit09911bf2008-07-26 23:55:29300 return;
[email protected]5dd768212009-08-13 23:34:49301 }
initial.commit09911bf2008-07-26 23:55:29302
303 const WebInputEvent* input_event =
304 reinterpret_cast<const WebInputEvent*>(data);
305 bool processed = false;
306 if (webwidget_)
[email protected]4873c7d2009-07-16 06:36:28307 processed = webwidget_->handleInputEvent(*input_event);
initial.commit09911bf2008-07-26 23:55:29308
309 IPC::Message* response = new ViewHostMsg_HandleInputEvent_ACK(routing_id_);
310 response->WriteInt(input_event->type);
[email protected]e2824412009-02-27 01:57:05311 response->WriteBool(processed);
312
initial.commit09911bf2008-07-26 23:55:29313 Send(response);
[email protected]5dd768212009-08-13 23:34:49314 handling_input_event_ = false;
initial.commit09911bf2008-07-26 23:55:29315}
316
317void RenderWidget::OnMouseCaptureLost() {
318 if (webwidget_)
[email protected]4873c7d2009-07-16 06:36:28319 webwidget_->mouseCaptureLost();
initial.commit09911bf2008-07-26 23:55:29320}
321
322void RenderWidget::OnSetFocus(bool enable) {
323 has_focus_ = enable;
324 if (webwidget_)
[email protected]4873c7d2009-07-16 06:36:28325 webwidget_->setFocus(enable);
initial.commit09911bf2008-07-26 23:55:29326 if (enable) {
327 // Force to retrieve the state of the focused widget to determine if we
328 // should activate IMEs next time when this process calls the UpdateIME()
329 // function.
330 ime_control_updated_ = true;
331 ime_control_new_state_ = true;
332 }
333}
334
335void RenderWidget::ClearFocus() {
336 // We may have got the focus from the browser before this gets processed, in
337 // which case we do not want to unfocus ourself.
338 if (!has_focus_ && webwidget_)
[email protected]4873c7d2009-07-16 06:36:28339 webwidget_->setFocus(false);
initial.commit09911bf2008-07-26 23:55:29340}
341
[email protected]2d5d09d52009-06-15 14:29:21342void RenderWidget::PaintRect(const gfx::Rect& rect,
343 skia::PlatformCanvas* canvas) {
344
345 // Bring the canvas into the coordinate system of the paint rect.
346 canvas->translate(static_cast<SkScalar>(-rect.x()),
347 static_cast<SkScalar>(-rect.y()));
[email protected]96c3499a2009-05-02 18:31:03348
[email protected]699ab0d2009-04-23 23:19:14349 // If there is a custom background, tile it.
350 if (!background_.empty()) {
[email protected]699ab0d2009-04-23 23:19:14351 SkPaint paint;
352 SkShader* shader = SkShader::CreateBitmapShader(background_,
353 SkShader::kRepeat_TileMode,
354 SkShader::kRepeat_TileMode);
355 paint.setShader(shader)->unref();
[email protected]8860e4f52009-06-25 01:01:52356 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
[email protected]699ab0d2009-04-23 23:19:14357 canvas->drawPaint(paint);
[email protected]699ab0d2009-04-23 23:19:14358 }
359
[email protected]8c89e7792009-08-19 21:18:34360 webwidget_->paint(webkit_glue::ToWebCanvas(canvas), rect);
initial.commit09911bf2008-07-26 23:55:29361
362 // Flush to underlying bitmap. TODO(darin): is this needed?
[email protected]661eb9d2009-02-03 02:11:48363 canvas->getTopPlatformDevice().accessBitmap(false);
initial.commit09911bf2008-07-26 23:55:29364}
365
initial.commit09911bf2008-07-26 23:55:29366void RenderWidget::DoDeferredPaint() {
[email protected]2d5d09d52009-06-15 14:29:21367 if (!webwidget_ || paint_reply_pending() || paint_rect_.IsEmpty())
initial.commit09911bf2008-07-26 23:55:29368 return;
369
370 // When we are hidden, we want to suppress painting, but we still need to
371 // mark this DoDeferredPaint as complete.
372 if (is_hidden_ || size_.IsEmpty()) {
[email protected]2d5d09d52009-06-15 14:29:21373 paint_rect_ = gfx::Rect();
initial.commit09911bf2008-07-26 23:55:29374 needs_repainting_on_restore_ = true;
375 return;
376 }
377
378 // Layout may generate more invalidation...
[email protected]4873c7d2009-07-16 06:36:28379 webwidget_->layout();
initial.commit09911bf2008-07-26 23:55:29380
381 // OK, save the current paint_rect to a local since painting may cause more
382 // invalidation. Some WebCore rendering objects only layout when painted.
[email protected]2d5d09d52009-06-15 14:29:21383 gfx::Rect damaged_rect = paint_rect_;
384 paint_rect_ = gfx::Rect();
initial.commit09911bf2008-07-26 23:55:29385
386 // Compute a buffer for painting and cache it.
[email protected]e68e62fa2009-02-20 02:00:04387 skia::PlatformCanvas* canvas =
[email protected]f09c7182009-03-10 12:54:04388 RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_,
[email protected]2d5d09d52009-06-15 14:29:21389 damaged_rect);
[email protected]e68e62fa2009-02-20 02:00:04390 if (!canvas) {
initial.commit09911bf2008-07-26 23:55:29391 NOTREACHED();
392 return;
393 }
394
[email protected]955ee6d62009-06-17 21:53:03395 // We may get back a smaller canvas than we asked for.
396 damaged_rect.set_width(canvas->getDevice()->width());
397 damaged_rect.set_height(canvas->getDevice()->height());
398
[email protected]2d5d09d52009-06-15 14:29:21399 PaintRect(damaged_rect, canvas);
initial.commit09911bf2008-07-26 23:55:29400
401 ViewHostMsg_PaintRect_Params params;
[email protected]2d5d09d52009-06-15 14:29:21402 params.bitmap_rect = damaged_rect;
initial.commit09911bf2008-07-26 23:55:29403 params.view_size = size_;
404 params.plugin_window_moves = plugin_window_moves_;
405 params.flags = next_paint_flags_;
[email protected]2d5d09d52009-06-15 14:29:21406 params.bitmap = current_paint_buf_->id();
initial.commit09911bf2008-07-26 23:55:29407
[email protected]e68e62fa2009-02-20 02:00:04408 delete canvas;
[email protected]661eb9d2009-02-03 02:11:48409
initial.commit09911bf2008-07-26 23:55:29410 plugin_window_moves_.clear();
411
412 paint_reply_pending_ = true;
413 Send(new ViewHostMsg_PaintRect(routing_id_, params));
414 next_paint_flags_ = 0;
415
416 UpdateIME();
417}
418
419void RenderWidget::DoDeferredScroll() {
420 if (!webwidget_ || scroll_reply_pending() || scroll_rect_.IsEmpty())
421 return;
422
423 // When we are hidden, we want to suppress scrolling, but we still need to
424 // mark this DoDeferredScroll as complete.
425 if (is_hidden_ || size_.IsEmpty()) {
426 scroll_rect_ = gfx::Rect();
427 needs_repainting_on_restore_ = true;
428 return;
429 }
430
431 // Layout may generate more invalidation, so we might have to bail on
432 // optimized scrolling...
[email protected]4873c7d2009-07-16 06:36:28433 webwidget_->layout();
initial.commit09911bf2008-07-26 23:55:29434
435 if (scroll_rect_.IsEmpty())
436 return;
437
438 gfx::Rect damaged_rect;
439
440 // Compute the region we will expose by scrolling, and paint that into a
441 // shared memory section.
442 if (scroll_delta_.x()) {
443 int dx = scroll_delta_.x();
444 damaged_rect.set_y(scroll_rect_.y());
445 damaged_rect.set_height(scroll_rect_.height());
446 if (dx > 0) {
447 damaged_rect.set_x(scroll_rect_.x());
448 damaged_rect.set_width(dx);
449 } else {
450 damaged_rect.set_x(scroll_rect_.right() + dx);
451 damaged_rect.set_width(-dx);
452 }
453 } else {
454 int dy = scroll_delta_.y();
455 damaged_rect.set_x(scroll_rect_.x());
456 damaged_rect.set_width(scroll_rect_.width());
457 if (dy > 0) {
458 damaged_rect.set_y(scroll_rect_.y());
459 damaged_rect.set_height(dy);
460 } else {
461 damaged_rect.set_y(scroll_rect_.bottom() + dy);
462 damaged_rect.set_height(-dy);
463 }
464 }
465
466 // In case the scroll offset exceeds the width/height of the scroll rect
467 damaged_rect = scroll_rect_.Intersect(damaged_rect);
468
[email protected]e68e62fa2009-02-20 02:00:04469 skia::PlatformCanvas* canvas =
[email protected]f09c7182009-03-10 12:54:04470 RenderProcess::current()->GetDrawingCanvas(&current_scroll_buf_,
471 damaged_rect);
[email protected]e68e62fa2009-02-20 02:00:04472 if (!canvas) {
initial.commit09911bf2008-07-26 23:55:29473 NOTREACHED();
474 return;
475 }
476
[email protected]955ee6d62009-06-17 21:53:03477 // We may get back a smaller canvas than we asked for.
478 damaged_rect.set_width(canvas->getDevice()->width());
479 damaged_rect.set_height(canvas->getDevice()->height());
480
initial.commit09911bf2008-07-26 23:55:29481 // Set these parameters before calling Paint, since that could result in
482 // further invalidates (uncommon).
483 ViewHostMsg_ScrollRect_Params params;
initial.commit09911bf2008-07-26 23:55:29484 params.bitmap_rect = damaged_rect;
485 params.dx = scroll_delta_.x();
486 params.dy = scroll_delta_.y();
487 params.clip_rect = scroll_rect_;
488 params.view_size = size_;
489 params.plugin_window_moves = plugin_window_moves_;
[email protected]e68e62fa2009-02-20 02:00:04490 params.bitmap = current_scroll_buf_->id();
[email protected]661eb9d2009-02-03 02:11:48491
initial.commit09911bf2008-07-26 23:55:29492 plugin_window_moves_.clear();
493
494 // Mark the scroll operation as no longer pending.
495 scroll_rect_ = gfx::Rect();
496
[email protected]e68e62fa2009-02-20 02:00:04497 PaintRect(damaged_rect, canvas);
initial.commit09911bf2008-07-26 23:55:29498 Send(new ViewHostMsg_ScrollRect(routing_id_, params));
[email protected]e68e62fa2009-02-20 02:00:04499 delete canvas;
initial.commit09911bf2008-07-26 23:55:29500 UpdateIME();
501}
502
503///////////////////////////////////////////////////////////////////////////////
504// WebWidgetDelegate
505
[email protected]4873c7d2009-07-16 06:36:28506void RenderWidget::didInvalidateRect(const WebRect& rect) {
initial.commit09911bf2008-07-26 23:55:29507 // We only want one pending DoDeferredPaint call at any time...
[email protected]2d5d09d52009-06-15 14:29:21508 bool paint_pending = !paint_rect_.IsEmpty();
initial.commit09911bf2008-07-26 23:55:29509
510 // If this invalidate overlaps with a pending scroll, then we have to
511 // downgrade to invalidating the scroll rect.
[email protected]b3f2b912009-04-09 16:18:52512 if (gfx::Rect(rect).Intersects(scroll_rect_)) {
[email protected]2d5d09d52009-06-15 14:29:21513 paint_rect_ = paint_rect_.Union(scroll_rect_);
initial.commit09911bf2008-07-26 23:55:29514 scroll_rect_ = gfx::Rect();
515 }
516
[email protected]2d5d09d52009-06-15 14:29:21517 gfx::Rect view_rect(0, 0, size_.width(), size_.height());
518 // TODO(iyengar) Investigate why we have painting issues when
519 // we ignore invalid regions outside the view.
520 // Ignore invalidates that occur outside the bounds of the view
521 // TODO(darin): maybe this should move into the paint code?
522 // paint_rect_ = view_rect.Intersect(paint_rect_.Union(rect));
523 paint_rect_ = paint_rect_.Union(view_rect.Intersect(rect));
initial.commit09911bf2008-07-26 23:55:29524
[email protected]2d5d09d52009-06-15 14:29:21525 if (paint_rect_.IsEmpty() || paint_reply_pending() || paint_pending)
initial.commit09911bf2008-07-26 23:55:29526 return;
527
528 // Perform painting asynchronously. This serves two purposes:
529 // 1) Ensures that we call WebView::Paint without a bunch of other junk
530 // on the call stack.
531 // 2) Allows us to collect more damage rects before painting to help coalesce
532 // the work that we will need to do.
533 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
534 this, &RenderWidget::DoDeferredPaint));
535}
536
[email protected]4873c7d2009-07-16 06:36:28537void RenderWidget::didScrollRect(int dx, int dy, const WebRect& clip_rect) {
[email protected]f911f742009-02-27 02:17:02538 if (dx != 0 && dy != 0) {
539 // We only support scrolling along one axis at a time.
[email protected]4873c7d2009-07-16 06:36:28540 didScrollRect(0, dy, clip_rect);
[email protected]f911f742009-02-27 02:17:02541 dy = 0;
542 }
initial.commit09911bf2008-07-26 23:55:29543
[email protected]2d5d09d52009-06-15 14:29:21544 bool intersects_with_painting = paint_rect_.Intersects(clip_rect);
initial.commit09911bf2008-07-26 23:55:29545
546 // If we already have a pending scroll operation or if this scroll operation
547 // intersects the existing paint region, then just failover to invalidating.
548 if (!scroll_rect_.IsEmpty() || intersects_with_painting) {
[email protected]b3f2b912009-04-09 16:18:52549 if (!intersects_with_painting && scroll_rect_ == gfx::Rect(clip_rect)) {
initial.commit09911bf2008-07-26 23:55:29550 // OK, we can just update the scroll delta (requires same scrolling axis)
551 if (!dx && !scroll_delta_.x()) {
552 scroll_delta_.set_y(scroll_delta_.y() + dy);
553 return;
554 }
555 if (!dy && !scroll_delta_.y()) {
556 scroll_delta_.set_x(scroll_delta_.x() + dx);
557 return;
558 }
559 }
[email protected]4873c7d2009-07-16 06:36:28560 didInvalidateRect(scroll_rect_);
initial.commit09911bf2008-07-26 23:55:29561 DCHECK(scroll_rect_.IsEmpty());
[email protected]4873c7d2009-07-16 06:36:28562 didInvalidateRect(clip_rect);
initial.commit09911bf2008-07-26 23:55:29563 return;
564 }
565
566 // We only want one pending DoDeferredScroll call at any time...
567 bool scroll_pending = !scroll_rect_.IsEmpty();
568
569 scroll_rect_ = clip_rect;
570 scroll_delta_.SetPoint(dx, dy);
571
572 if (scroll_pending)
573 return;
574
575 // Perform scrolling asynchronously since we need to call WebView::Paint
576 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
577 this, &RenderWidget::DoDeferredScroll));
578}
579
[email protected]4873c7d2009-07-16 06:36:28580void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) {
[email protected]7c51b0ee2009-07-08 21:49:30581 // TODO(darin): Eliminate this temporary.
582 WebCursor cursor(cursor_info);
583
initial.commit09911bf2008-07-26 23:55:29584 // Only send a SetCursor message if we need to make a change.
585 if (!current_cursor_.IsEqual(cursor)) {
586 current_cursor_ = cursor;
587 Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
588 }
589}
590
591// We are supposed to get a single call to Show for a newly created RenderWidget
592// that was created via RenderWidget::CreateWebView. So, we wait until this
593// point to dispatch the ShowWidget message.
594//
595// This method provides us with the information about how to display the newly
596// created RenderWidget (i.e., as a constrained popup or as a new tab).
597//
[email protected]4873c7d2009-07-16 06:36:28598void RenderWidget::show(WebNavigationPolicy) {
initial.commit09911bf2008-07-26 23:55:29599 DCHECK(!did_show_) << "received extraneous Show call";
600 DCHECK(routing_id_ != MSG_ROUTING_NONE);
601 DCHECK(opener_id_ != MSG_ROUTING_NONE);
602
603 if (!did_show_) {
604 did_show_ = true;
605 // NOTE: initial_pos_ may still have its default values at this point, but
606 // that's okay. It'll be ignored if as_popup is false, or the browser
607 // process will impose a default position otherwise.
[email protected]88efb7ec2009-07-14 16:32:59608 if (popup_params_.get()) {
609 popup_params_->bounds = initial_pos_;
610 Send(new ViewHostMsg_ShowPopup(routing_id_, *popup_params_));
611 popup_params_.reset();
612 } else {
613 Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_pos_));
614 }
[email protected]2533ce12009-05-09 00:02:24615 SetPendingWindowRect(initial_pos_);
initial.commit09911bf2008-07-26 23:55:29616 }
617}
618
[email protected]4873c7d2009-07-16 06:36:28619void RenderWidget::didFocus() {
initial.commit09911bf2008-07-26 23:55:29620 // Prevent the widget from stealing the focus if it does not have focus
621 // already. We do this by explicitely setting the focus to false again.
622 // We only let the browser focus the renderer.
623 if (!has_focus_ && webwidget_) {
624 MessageLoop::current()->PostTask(FROM_HERE,
625 NewRunnableMethod(this, &RenderWidget::ClearFocus));
626 }
627}
628
[email protected]4873c7d2009-07-16 06:36:28629void RenderWidget::didBlur() {
initial.commit09911bf2008-07-26 23:55:29630 Send(new ViewHostMsg_Blur(routing_id_));
631}
632
[email protected]2533ce12009-05-09 00:02:24633void RenderWidget::DoDeferredClose() {
634 Send(new ViewHostMsg_Close(routing_id_));
635}
636
[email protected]4873c7d2009-07-16 06:36:28637void RenderWidget::closeWidgetSoon() {
initial.commit09911bf2008-07-26 23:55:29638 // If a page calls window.close() twice, we'll end up here twice, but that's
639 // OK. It is safe to send multiple Close messages.
640
[email protected]2533ce12009-05-09 00:02:24641 // Ask the RenderWidgetHost to initiate close. We could be called from deep
642 // in Javascript. If we ask the RendwerWidgetHost to close now, the window
643 // could be closed before the JS finishes executing. So instead, post a
644 // message back to the message loop, which won't run until the JS is
645 // complete, and then the Close message can be sent.
[email protected]75ae4492009-07-10 00:05:15646 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]2533ce12009-05-09 00:02:24647 this, &RenderWidget::DoDeferredClose));
initial.commit09911bf2008-07-26 23:55:29648}
649
[email protected]b4b967e2009-04-22 11:33:05650void RenderWidget::GenerateFullRepaint() {
[email protected]4873c7d2009-07-16 06:36:28651 didInvalidateRect(gfx::Rect(size_.width(), size_.height()));
[email protected]b4b967e2009-04-22 11:33:05652}
653
initial.commit09911bf2008-07-26 23:55:29654void RenderWidget::Close() {
655 if (webwidget_) {
[email protected]4873c7d2009-07-16 06:36:28656 webwidget_->close();
initial.commit09911bf2008-07-26 23:55:29657 webwidget_ = NULL;
658 }
659}
660
[email protected]4873c7d2009-07-16 06:36:28661WebRect RenderWidget::windowRect() {
662 if (pending_window_rect_count_)
663 return pending_window_rect_;
[email protected]2533ce12009-05-09 00:02:24664
[email protected]b3f2b912009-04-09 16:18:52665 gfx::Rect rect;
666 Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, &rect));
[email protected]4873c7d2009-07-16 06:36:28667 return rect;
initial.commit09911bf2008-07-26 23:55:29668}
669
[email protected]4873c7d2009-07-16 06:36:28670void RenderWidget::setWindowRect(const WebRect& pos) {
initial.commit09911bf2008-07-26 23:55:29671 if (did_show_) {
672 Send(new ViewHostMsg_RequestMove(routing_id_, pos));
[email protected]2533ce12009-05-09 00:02:24673 SetPendingWindowRect(pos);
initial.commit09911bf2008-07-26 23:55:29674 } else {
675 initial_pos_ = pos;
676 }
677}
678
[email protected]2533ce12009-05-09 00:02:24679void RenderWidget::SetPendingWindowRect(const WebRect& rect) {
680 pending_window_rect_ = rect;
681 pending_window_rect_count_++;
682}
683
[email protected]4873c7d2009-07-16 06:36:28684WebRect RenderWidget::rootWindowRect() {
[email protected]2533ce12009-05-09 00:02:24685 if (pending_window_rect_count_) {
686 // NOTE(mbelshe): If there is a pending_window_rect_, then getting
687 // the RootWindowRect is probably going to return wrong results since the
688 // browser may not have processed the Move yet. There isn't really anything
689 // good to do in this case, and it shouldn't happen - since this size is
690 // only really needed for windowToScreen, which is only used for Popups.
[email protected]4873c7d2009-07-16 06:36:28691 return pending_window_rect_;
[email protected]2533ce12009-05-09 00:02:24692 }
693
[email protected]b3f2b912009-04-09 16:18:52694 gfx::Rect rect;
695 Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, &rect));
[email protected]4873c7d2009-07-16 06:36:28696 return rect;
[email protected]d4547452008-08-28 18:36:37697}
698
[email protected]4873c7d2009-07-16 06:36:28699WebRect RenderWidget::windowResizerRect() {
700 return resizer_rect_;
[email protected]c04b6362008-11-21 18:54:19701}
702
initial.commit09911bf2008-07-26 23:55:29703void RenderWidget::OnImeSetInputMode(bool is_active) {
[email protected]c4bb35a2008-10-31 17:54:03704 // To prevent this renderer process from sending unnecessary IPC messages to
705 // a browser process, we permit the renderer process to send IPC messages
706 // only during the IME attached to the browser process is active.
initial.commit09911bf2008-07-26 23:55:29707 ime_is_active_ = is_active;
initial.commit09911bf2008-07-26 23:55:29708}
709
[email protected]4873c7d2009-07-16 06:36:28710void RenderWidget::OnImeSetComposition(WebCompositionCommand command,
initial.commit09911bf2008-07-26 23:55:29711 int cursor_position,
712 int target_start, int target_end,
[email protected]4873c7d2009-07-16 06:36:28713 const string16& ime_string) {
714 if (!webwidget_)
715 return;
716 ime_control_busy_ = true;
717 webwidget_->handleCompositionEvent(command, cursor_position,
718 target_start, target_end,
719 ime_string);
720 ime_control_busy_ = false;
initial.commit09911bf2008-07-26 23:55:29721}
722
[email protected]ec7dc112008-08-06 05:30:12723void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) {
724 // During shutdown we can just ignore this message.
725 if (!webwidget_)
726 return;
727
728 set_next_paint_is_repaint_ack();
729 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height());
[email protected]4873c7d2009-07-16 06:36:28730 didInvalidateRect(repaint_rect);
[email protected]ec7dc112008-08-06 05:30:12731}
732
[email protected]4873c7d2009-07-16 06:36:28733void RenderWidget::OnSetTextDirection(WebTextDirection direction) {
[email protected]07f953332009-03-25 04:31:11734 if (!webwidget_)
735 return;
[email protected]4873c7d2009-07-16 06:36:28736 webwidget_->setTextDirection(direction);
[email protected]07f953332009-03-25 04:31:11737}
738
[email protected]699ab0d2009-04-23 23:19:14739void RenderWidget::SetBackground(const SkBitmap& background) {
740 background_ = background;
741 // Generate a full repaint.
[email protected]4873c7d2009-07-16 06:36:28742 didInvalidateRect(gfx::Rect(size_.width(), size_.height()));
[email protected]699ab0d2009-04-23 23:19:14743}
744
[email protected]674741932009-02-04 23:44:46745bool RenderWidget::next_paint_is_resize_ack() const {
746 return ViewHostMsg_PaintRect_Flags::is_resize_ack(next_paint_flags_);
747}
748
749bool RenderWidget::next_paint_is_restore_ack() const {
750 return ViewHostMsg_PaintRect_Flags::is_restore_ack(next_paint_flags_);
751}
752
753void RenderWidget::set_next_paint_is_resize_ack() {
754 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESIZE_ACK;
755}
756
757void RenderWidget::set_next_paint_is_restore_ack() {
758 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESTORE_ACK;
759}
760
761void RenderWidget::set_next_paint_is_repaint_ack() {
762 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_REPAINT_ACK;
763}
764
initial.commit09911bf2008-07-26 23:55:29765void RenderWidget::UpdateIME() {
766 // If a browser process does not have IMEs, its IMEs are not active, or there
767 // are not any attached widgets.
768 // a renderer process does not have to retrieve information of the focused
769 // control or send notification messages to a browser process.
770 if (!ime_is_active_) {
771 return;
772 }
[email protected]34f6bc12008-11-06 07:40:53773 // Retrieve the caret position from the focused widget and verify we should
774 // enabled IMEs attached to the browser process.
775 bool enable_ime = false;
[email protected]b3f2b912009-04-09 16:18:52776 WebRect caret_rect;
[email protected]34f6bc12008-11-06 07:40:53777 if (!webwidget_ ||
[email protected]4873c7d2009-07-16 06:36:28778 !webwidget_->queryCompositionStatus(&enable_ime, &caret_rect)) {
initial.commit09911bf2008-07-26 23:55:29779 // There are not any editable widgets attached to this process.
780 // We should disable the IME to prevent it from sending CJK strings to
781 // non-editable widgets.
782 ime_control_updated_ = true;
783 ime_control_new_state_ = false;
784 }
[email protected]9f23f592008-11-17 08:36:34785 if (ime_control_new_state_ != enable_ime) {
786 ime_control_updated_ = true;
787 ime_control_new_state_ = enable_ime;
788 }
initial.commit09911bf2008-07-26 23:55:29789 if (ime_control_updated_) {
790 // The input focus has been changed.
791 // Compare the current state with the updated state and choose actions.
792 if (ime_control_enable_ime_) {
793 if (ime_control_new_state_) {
794 // Case 1: a text input -> another text input
795 // Complete the current composition and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53796 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
797 IME_COMPLETE_COMPOSITION,
798 caret_rect));
initial.commit09911bf2008-07-26 23:55:29799 } else {
800 // Case 2: a text input -> a password input (or a static control)
801 // Complete the current composition and disable the IME.
[email protected]34f6bc12008-11-06 07:40:53802 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_DISABLE,
803 caret_rect));
initial.commit09911bf2008-07-26 23:55:29804 }
805 } else {
806 if (ime_control_new_state_) {
807 // Case 3: a password input (or a static control) -> a text input
808 // Enable the IME and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53809 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
810 IME_COMPLETE_COMPOSITION,
811 caret_rect));
initial.commit09911bf2008-07-26 23:55:29812 } else {
813 // Case 4: a password input (or a static contol) -> another password
814 // input (or another static control).
815 // The IME has been already disabled and we don't have to do anything.
816 }
817 }
818 } else {
819 // The input focus is not changed.
820 // Notify the caret position to a browser process only if it is changed.
821 if (ime_control_enable_ime_) {
[email protected]b3f2b912009-04-09 16:18:52822 if (caret_rect.x != ime_control_x_ ||
823 caret_rect.y != ime_control_y_) {
[email protected]34f6bc12008-11-06 07:40:53824 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_MOVE_WINDOWS,
825 caret_rect));
initial.commit09911bf2008-07-26 23:55:29826 }
827 }
828 }
829 // Save the updated IME status to prevent from sending the same IPC messages.
830 ime_control_updated_ = false;
831 ime_control_enable_ime_ = ime_control_new_state_;
[email protected]b3f2b912009-04-09 16:18:52832 ime_control_x_ = caret_rect.x;
833 ime_control_y_ = caret_rect.y;
initial.commit09911bf2008-07-26 23:55:29834}
835
[email protected]4873c7d2009-07-16 06:36:28836WebScreenInfo RenderWidget::screenInfo() {
837 WebScreenInfo results;
838 Send(new ViewHostMsg_GetScreenInfo(routing_id_, host_window_, &results));
839 return results;
840}
841
842void RenderWidget::SchedulePluginMove(const WebPluginGeometry& move) {
initial.commit09911bf2008-07-26 23:55:29843 size_t i = 0;
844 for (; i < plugin_window_moves_.size(); ++i) {
845 if (plugin_window_moves_[i].window == move.window) {
846 plugin_window_moves_[i] = move;
847 break;
848 }
849 }
850
851 if (i == plugin_window_moves_.size())
852 plugin_window_moves_.push_back(move);
853}
[email protected]268654772009-08-06 23:02:04854
855void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) {
856 for (WebPluginGeometryVector::iterator i = plugin_window_moves_.begin();
857 i != plugin_window_moves_.end(); ++i) {
858 if (i->window == window) {
859 plugin_window_moves_.erase(i);
860 break;
861 }
862 }
863}