blob: 874768be7d3cba26d6352196cc0a37c0f9bebeb6 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
5#include "chrome/renderer/render_widget.h"
6
7#include <windows.h>
8
9#include "base/gfx/point.h"
10#include "base/gfx/size.h"
11#include "base/logging.h"
12#include "base/message_loop.h"
[email protected]b49cbcf22008-08-14 17:47:0013#include "base/gfx/platform_canvas_win.h"
initial.commit09911bf2008-07-26 23:55:2914#include "base/scoped_ptr.h"
[email protected]8085dbc82008-09-26 22:53:4415#include "chrome/renderer/render_process.h"
16
initial.commit09911bf2008-07-26 23:55:2917#include "webkit/glue/webinputevent.h"
18#include "webkit/glue/webwidget.h"
19
20///////////////////////////////////////////////////////////////////////////////
21
22namespace {
23
24// This class is used to defer calling RenderWidget::Close() while the current
25// thread is inside RenderThread::Send(), which in some cases can result in a
26// nested MessageLoop being run.
27class DeferredCloses : public Task {
28 public:
29 // Called to queue a deferred close for the given widget.
30 static void Push(RenderWidget* widget) {
31 if (!current_)
32 current_ = new DeferredCloses();
33 current_->queue_.push(widget);
34 }
35
36 // Called to trigger any deferred closes to be run.
37 static void Post() {
initial.commit09911bf2008-07-26 23:55:2938 if (current_) {
39 MessageLoop::current()->PostTask(FROM_HERE, current_);
40 current_ = NULL;
41 }
42 }
43
44 private:
45 virtual void Run() {
46 // Maybe we are being run from within another RenderWidget::Send call. If
47 // that is true, then we need to re-queue the widgets to be closed and try
48 // again later.
49 while (!queue_.empty()) {
[email protected]8085dbc82008-09-26 22:53:4450 if (queue_.front()->InSend()) {
initial.commit09911bf2008-07-26 23:55:2951 Push(queue_.front());
52 } else {
53 queue_.front()->Close();
54 }
55 queue_.pop();
56 }
57 }
58
59 // The current DeferredCloses object.
60 static DeferredCloses* current_;
61
62 typedef std::queue< scoped_refptr<RenderWidget> > WidgetQueue;
63 WidgetQueue queue_;
64};
65
66DeferredCloses* DeferredCloses::current_ = NULL;
67
68} // namespace
69
70///////////////////////////////////////////////////////////////////////////////
71
[email protected]8085dbc82008-09-26 22:53:4472RenderWidget::RenderWidget(RenderThreadBase* render_thread)
initial.commit09911bf2008-07-26 23:55:2973 : routing_id_(MSG_ROUTING_NONE),
74 opener_id_(MSG_ROUTING_NONE),
[email protected]8085dbc82008-09-26 22:53:4475 render_thread_(render_thread),
initial.commit09911bf2008-07-26 23:55:2976 host_window_(NULL),
77 current_paint_buf_(NULL),
78 current_scroll_buf_(NULL),
79 next_paint_flags_(0),
80 paint_reply_pending_(false),
81 did_show_(false),
82 closing_(false),
83 is_hidden_(false),
84 needs_repainting_on_restore_(false),
85 has_focus_(false),
86 ime_is_active_(false),
87 ime_control_enable_ime_(true),
88 ime_control_x_(-1),
89 ime_control_y_(-1),
90 ime_control_new_state_(false),
91 ime_control_updated_(false) {
92 RenderProcess::AddRefProcess();
[email protected]8085dbc82008-09-26 22:53:4493 DCHECK(render_thread_);
initial.commit09911bf2008-07-26 23:55:2994}
95
96RenderWidget::~RenderWidget() {
97 if (current_paint_buf_) {
98 RenderProcess::FreeSharedMemory(current_paint_buf_);
99 current_paint_buf_ = NULL;
100 }
101 if (current_scroll_buf_) {
102 RenderProcess::FreeSharedMemory(current_scroll_buf_);
103 current_scroll_buf_ = NULL;
104 }
105 RenderProcess::ReleaseProcess();
106}
107
108/*static*/
[email protected]8085dbc82008-09-26 22:53:44109RenderWidget* RenderWidget::Create(int32 opener_id,
110 RenderThreadBase* render_thread) {
initial.commit09911bf2008-07-26 23:55:29111 DCHECK(opener_id != MSG_ROUTING_NONE);
[email protected]8085dbc82008-09-26 22:53:44112 scoped_refptr<RenderWidget> widget = new RenderWidget(render_thread);
initial.commit09911bf2008-07-26 23:55:29113 widget->Init(opener_id); // adds reference
114 return widget;
115}
116
117void RenderWidget::Init(int32 opener_id) {
118 DCHECK(!webwidget_);
119
120 if (opener_id != MSG_ROUTING_NONE)
121 opener_id_ = opener_id;
122
123 // Avoid a leak here by not assigning, since WebWidget::Create addrefs for us.
124 WebWidget* webwidget = WebWidget::Create(this);
125 webwidget_.swap(&webwidget);
126
[email protected]8085dbc82008-09-26 22:53:44127 bool result = render_thread_->Send(
initial.commit09911bf2008-07-26 23:55:29128 new ViewHostMsg_CreateWidget(opener_id, &routing_id_));
129 if (result) {
[email protected]8085dbc82008-09-26 22:53:44130 render_thread_->AddRoute(routing_id_, this);
initial.commit09911bf2008-07-26 23:55:29131 // Take a reference on behalf of the RenderThread. This will be balanced
132 // when we receive ViewMsg_Close.
133 AddRef();
134 } else {
135 DCHECK(false);
136 }
137}
138
139// This is used to complete pending inits and non-pending inits. For non-
140// pending cases, the parent will be the same as the current parent. This
141// indicates we do not need to reparent or anything.
142void RenderWidget::CompleteInit(HWND parent_hwnd) {
143 DCHECK(routing_id_ != MSG_ROUTING_NONE);
144 DCHECK(parent_hwnd);
145
146 host_window_ = parent_hwnd;
147
148 Send(new ViewHostMsg_RendererReady(routing_id_));
149}
150
151IPC_DEFINE_MESSAGE_MAP(RenderWidget)
152 IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
153 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
154 IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize)
155 IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden)
156 IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored)
157 IPC_MESSAGE_HANDLER(ViewMsg_PaintRect_ACK, OnPaintRectAck)
158 IPC_MESSAGE_HANDLER(ViewMsg_ScrollRect_ACK, OnScrollRectAck)
159 IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent)
160 IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost)
161 IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus)
162 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetInputMode, OnImeSetInputMode)
163 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition)
[email protected]ec7dc112008-08-06 05:30:12164 IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint)
initial.commit09911bf2008-07-26 23:55:29165 IPC_MESSAGE_UNHANDLED_ERROR()
166IPC_END_MESSAGE_MAP()
167
168bool RenderWidget::Send(IPC::Message* message) {
169 // Don't send any messages after the browser has told us to close.
170 if (closing_) {
171 delete message;
172 return false;
173 }
174
175 // If given a messsage without a routing ID, then assign our routing ID.
176 if (message->routing_id() == MSG_ROUTING_NONE)
177 message->set_routing_id(routing_id_);
178
[email protected]8085dbc82008-09-26 22:53:44179 bool rv = render_thread_->Send(message);
initial.commit09911bf2008-07-26 23:55:29180
181 // If there aren't any more RenderThread::Send calls on the stack, then we
182 // can go ahead and schedule Close to be called on any RenderWidget objects
183 // that received a ViewMsg_Close while we were inside Send.
[email protected]8085dbc82008-09-26 22:53:44184 if (!render_thread_->InSend())
initial.commit09911bf2008-07-26 23:55:29185 DeferredCloses::Post();
186
187 return rv;
188}
189
[email protected]8085dbc82008-09-26 22:53:44190bool RenderWidget::InSend() const {
191 return render_thread_->InSend();
192}
193
initial.commit09911bf2008-07-26 23:55:29194// Got a response from the browser after the renderer decided to create a new
195// view.
196void RenderWidget::OnCreatingNewAck(HWND parent) {
197 DCHECK(routing_id_ != MSG_ROUTING_NONE);
198
199 CompleteInit(parent);
200}
201
202void RenderWidget::OnClose() {
203 if (closing_)
204 return;
205 closing_ = true;
206
207 // Browser correspondence is no longer needed at this point.
208 if (routing_id_ != MSG_ROUTING_NONE)
[email protected]8085dbc82008-09-26 22:53:44209 render_thread_->RemoveRoute(routing_id_);
initial.commit09911bf2008-07-26 23:55:29210
211 // Balances the AddRef taken when we called AddRoute. This release happens
212 // via the MessageLoop since it may cause our destruction.
213 MessageLoop::current()->ReleaseSoon(FROM_HERE, this);
214
215 // If there is a Send call on the stack, then it could be dangerous to close
216 // now. Instead, we wait until we get out of Send.
[email protected]8085dbc82008-09-26 22:53:44217 if (render_thread_->InSend()) {
initial.commit09911bf2008-07-26 23:55:29218 DeferredCloses::Push(this);
219 } else {
220 Close();
221 }
222}
223
224void RenderWidget::OnResize(const gfx::Size& new_size) {
225 // During shutdown we can just ignore this message.
226 if (!webwidget_)
227 return;
228
229 // TODO(darin): We should not need to reset this here.
230 is_hidden_ = false;
231 needs_repainting_on_restore_ = false;
232
233 // We shouldn't be asked to resize to our current size.
234 DCHECK(size_ != new_size);
235 size_ = new_size;
236
237 // We should not be sent a Resize message if we have not ACK'd the previous
238 DCHECK(!next_paint_is_resize_ack());
239
240 // When resizing, we want to wait to paint before ACK'ing the resize. This
241 // ensures that we only resize as fast as we can paint. We only need to send
242 // an ACK if we are resized to a non-empty rect.
243 webwidget_->Resize(new_size);
244 if (!new_size.IsEmpty()) {
245 DCHECK(!paint_rect_.IsEmpty());
246
247 // This should have caused an invalidation of the entire view. The damaged
248 // rect could be larger than new_size if we are being made smaller.
249 DCHECK_GE(paint_rect_.width(), new_size.width());
250 DCHECK_GE(paint_rect_.height(), new_size.height());
251
252 // We will send the Resize_ACK flag once we paint again.
253 set_next_paint_is_resize_ack();
254 }
255}
256
257void RenderWidget::OnWasHidden() {
258 // Go into a mode where we stop generating paint and scrolling events.
259 is_hidden_ = true;
260}
261
262void RenderWidget::OnWasRestored(bool needs_repainting) {
263 // During shutdown we can just ignore this message.
264 if (!webwidget_)
265 return;
266
267 // See OnWasHidden
268 is_hidden_ = false;
269
270 if (!needs_repainting && !needs_repainting_on_restore_)
271 return;
272 needs_repainting_on_restore_ = false;
273
274 // Tag the next paint as a restore ack, which is picked up by DoDeferredPaint
275 // when it sends out the next PaintRect message.
276 set_next_paint_is_restore_ack();
277
278 // Generate a full repaint.
279 DidInvalidateRect(webwidget_, gfx::Rect(size_.width(), size_.height()));
280}
281
[email protected]b7fce1f2008-08-14 05:01:07282void RenderWidget::OnPaintRectAck() {
initial.commit09911bf2008-07-26 23:55:29283 DCHECK(paint_reply_pending());
284 paint_reply_pending_ = false;
[email protected]b7fce1f2008-08-14 05:01:07285 // If we sent a PaintRect message with a zero-sized bitmap, then
286 // we should have no current paint buf.
287 if (current_paint_buf_) {
288 RenderProcess::FreeSharedMemory(current_paint_buf_);
289 current_paint_buf_ = NULL;
initial.commit09911bf2008-07-26 23:55:29290 }
initial.commit09911bf2008-07-26 23:55:29291 // Continue painting if necessary...
292 DoDeferredPaint();
293}
294
295void RenderWidget::OnScrollRectAck() {
296 DCHECK(scroll_reply_pending());
297
298 RenderProcess::FreeSharedMemory(current_scroll_buf_);
299 current_scroll_buf_ = NULL;
300
301 // Continue scrolling if necessary...
302 DoDeferredScroll();
303}
304
305void RenderWidget::OnHandleInputEvent(const IPC::Message& message) {
306 void* iter = NULL;
307
308 const char* data;
309 int data_length;
310 if (!message.ReadData(&iter, &data, &data_length))
311 return;
312
313 const WebInputEvent* input_event =
314 reinterpret_cast<const WebInputEvent*>(data);
315 bool processed = false;
316 if (webwidget_)
317 processed = webwidget_->HandleInputEvent(input_event);
318
319 IPC::Message* response = new ViewHostMsg_HandleInputEvent_ACK(routing_id_);
320 response->WriteInt(input_event->type);
321 if (!processed) {
322 // If the event was not processed we send it back.
323 response->WriteData(data, data_length);
324 }
325 Send(response);
326}
327
328void RenderWidget::OnMouseCaptureLost() {
329 if (webwidget_)
330 webwidget_->MouseCaptureLost();
331}
332
333void RenderWidget::OnSetFocus(bool enable) {
334 has_focus_ = enable;
335 if (webwidget_)
336 webwidget_->SetFocus(enable);
337 if (enable) {
338 // Force to retrieve the state of the focused widget to determine if we
339 // should activate IMEs next time when this process calls the UpdateIME()
340 // function.
341 ime_control_updated_ = true;
342 ime_control_new_state_ = true;
343 }
344}
345
346void RenderWidget::ClearFocus() {
347 // We may have got the focus from the browser before this gets processed, in
348 // which case we do not want to unfocus ourself.
349 if (!has_focus_ && webwidget_)
350 webwidget_->SetFocus(false);
351}
352
353void RenderWidget::PaintRect(const gfx::Rect& rect, SharedMemory* paint_buf) {
[email protected]b49cbcf22008-08-14 17:47:00354 gfx::PlatformCanvasWin canvas(rect.width(), rect.height(), true,
initial.commit09911bf2008-07-26 23:55:29355 paint_buf->handle());
356 // Bring the canvas into the coordinate system of the paint rect
357 canvas.translate(static_cast<SkScalar>(-rect.x()),
358 static_cast<SkScalar>(-rect.y()));
359
360 webwidget_->Paint(&canvas, rect);
361
362 // Flush to underlying bitmap. TODO(darin): is this needed?
363 canvas.getTopPlatformDevice().accessBitmap(false);
364
365 // Let the subclass observe this paint operations.
366 DidPaint();
367}
368
369size_t RenderWidget::GetPaintBufSize(const gfx::Rect& rect) {
370 // TODO(darin): protect against overflow
371 return 4 * rect.width() * rect.height();
372}
373
374void RenderWidget::DoDeferredPaint() {
375 if (!webwidget_ || paint_reply_pending() || paint_rect_.IsEmpty())
376 return;
377
378 // When we are hidden, we want to suppress painting, but we still need to
379 // mark this DoDeferredPaint as complete.
380 if (is_hidden_ || size_.IsEmpty()) {
381 paint_rect_ = gfx::Rect();
382 needs_repainting_on_restore_ = true;
383 return;
384 }
385
386 // Layout may generate more invalidation...
387 webwidget_->Layout();
388
389 // OK, save the current paint_rect to a local since painting may cause more
390 // invalidation. Some WebCore rendering objects only layout when painted.
391 gfx::Rect damaged_rect = paint_rect_;
392 paint_rect_ = gfx::Rect();
393
394 // Compute a buffer for painting and cache it.
395 current_paint_buf_ =
396 RenderProcess::AllocSharedMemory(GetPaintBufSize(damaged_rect));
397 if (!current_paint_buf_) {
398 NOTREACHED();
399 return;
400 }
401
402 PaintRect(damaged_rect, current_paint_buf_);
403
404 ViewHostMsg_PaintRect_Params params;
405 params.bitmap = current_paint_buf_->handle();
406 params.bitmap_rect = damaged_rect;
407 params.view_size = size_;
408 params.plugin_window_moves = plugin_window_moves_;
409 params.flags = next_paint_flags_;
410
411 plugin_window_moves_.clear();
412
413 paint_reply_pending_ = true;
414 Send(new ViewHostMsg_PaintRect(routing_id_, params));
415 next_paint_flags_ = 0;
416
417 UpdateIME();
418}
419
420void RenderWidget::DoDeferredScroll() {
421 if (!webwidget_ || scroll_reply_pending() || scroll_rect_.IsEmpty())
422 return;
423
424 // When we are hidden, we want to suppress scrolling, but we still need to
425 // mark this DoDeferredScroll as complete.
426 if (is_hidden_ || size_.IsEmpty()) {
427 scroll_rect_ = gfx::Rect();
428 needs_repainting_on_restore_ = true;
429 return;
430 }
431
432 // Layout may generate more invalidation, so we might have to bail on
433 // optimized scrolling...
434 webwidget_->Layout();
435
436 if (scroll_rect_.IsEmpty())
437 return;
438
439 gfx::Rect damaged_rect;
440
441 // Compute the region we will expose by scrolling, and paint that into a
442 // shared memory section.
443 if (scroll_delta_.x()) {
444 int dx = scroll_delta_.x();
445 damaged_rect.set_y(scroll_rect_.y());
446 damaged_rect.set_height(scroll_rect_.height());
447 if (dx > 0) {
448 damaged_rect.set_x(scroll_rect_.x());
449 damaged_rect.set_width(dx);
450 } else {
451 damaged_rect.set_x(scroll_rect_.right() + dx);
452 damaged_rect.set_width(-dx);
453 }
454 } else {
455 int dy = scroll_delta_.y();
456 damaged_rect.set_x(scroll_rect_.x());
457 damaged_rect.set_width(scroll_rect_.width());
458 if (dy > 0) {
459 damaged_rect.set_y(scroll_rect_.y());
460 damaged_rect.set_height(dy);
461 } else {
462 damaged_rect.set_y(scroll_rect_.bottom() + dy);
463 damaged_rect.set_height(-dy);
464 }
465 }
466
467 // In case the scroll offset exceeds the width/height of the scroll rect
468 damaged_rect = scroll_rect_.Intersect(damaged_rect);
469
470 current_scroll_buf_ =
471 RenderProcess::AllocSharedMemory(GetPaintBufSize(damaged_rect));
472 if (!current_scroll_buf_) {
473 NOTREACHED();
474 return;
475 }
476
477 // Set these parameters before calling Paint, since that could result in
478 // further invalidates (uncommon).
479 ViewHostMsg_ScrollRect_Params params;
480 params.bitmap = current_scroll_buf_->handle();
481 params.bitmap_rect = damaged_rect;
482 params.dx = scroll_delta_.x();
483 params.dy = scroll_delta_.y();
484 params.clip_rect = scroll_rect_;
485 params.view_size = size_;
486 params.plugin_window_moves = plugin_window_moves_;
487
488 plugin_window_moves_.clear();
489
490 // Mark the scroll operation as no longer pending.
491 scroll_rect_ = gfx::Rect();
492
493 PaintRect(damaged_rect, current_scroll_buf_);
494 Send(new ViewHostMsg_ScrollRect(routing_id_, params));
495 UpdateIME();
496}
497
498///////////////////////////////////////////////////////////////////////////////
499// WebWidgetDelegate
500
501HWND RenderWidget::GetContainingWindow(WebWidget* webwidget) {
502 return host_window_;
503}
504
505void RenderWidget::DidInvalidateRect(WebWidget* webwidget,
506 const gfx::Rect& rect) {
507 // We only want one pending DoDeferredPaint call at any time...
508 bool paint_pending = !paint_rect_.IsEmpty();
509
510 // If this invalidate overlaps with a pending scroll, then we have to
511 // downgrade to invalidating the scroll rect.
512 if (rect.Intersects(scroll_rect_)) {
513 paint_rect_ = paint_rect_.Union(scroll_rect_);
514 scroll_rect_ = gfx::Rect();
515 }
516
517 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));
524
525 if (paint_rect_.IsEmpty() || paint_reply_pending() || paint_pending)
526 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
537void RenderWidget::DidScrollRect(WebWidget* webwidget, int dx, int dy,
538 const gfx::Rect& clip_rect) {
539 // We only support scrolling along one axis at a time.
540 DCHECK((dx && !dy) || (!dx && dy));
541
542 bool intersects_with_painting = paint_rect_.Intersects(clip_rect);
543
544 // If we already have a pending scroll operation or if this scroll operation
545 // intersects the existing paint region, then just failover to invalidating.
546 if (!scroll_rect_.IsEmpty() || intersects_with_painting) {
547 if (!intersects_with_painting && scroll_rect_ == clip_rect) {
548 // OK, we can just update the scroll delta (requires same scrolling axis)
549 if (!dx && !scroll_delta_.x()) {
550 scroll_delta_.set_y(scroll_delta_.y() + dy);
551 return;
552 }
553 if (!dy && !scroll_delta_.y()) {
554 scroll_delta_.set_x(scroll_delta_.x() + dx);
555 return;
556 }
557 }
558 DidInvalidateRect(webwidget_, scroll_rect_);
559 DCHECK(scroll_rect_.IsEmpty());
560 DidInvalidateRect(webwidget_, clip_rect);
561 return;
562 }
563
564 // We only want one pending DoDeferredScroll call at any time...
565 bool scroll_pending = !scroll_rect_.IsEmpty();
566
567 scroll_rect_ = clip_rect;
568 scroll_delta_.SetPoint(dx, dy);
569
570 if (scroll_pending)
571 return;
572
573 // Perform scrolling asynchronously since we need to call WebView::Paint
574 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
575 this, &RenderWidget::DoDeferredScroll));
576}
577
578void RenderWidget::SetCursor(WebWidget* webwidget, const WebCursor& cursor) {
579 // Only send a SetCursor message if we need to make a change.
580 if (!current_cursor_.IsEqual(cursor)) {
581 current_cursor_ = cursor;
582 Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
583 }
584}
585
586// We are supposed to get a single call to Show for a newly created RenderWidget
587// that was created via RenderWidget::CreateWebView. So, we wait until this
588// point to dispatch the ShowWidget message.
589//
590// This method provides us with the information about how to display the newly
591// created RenderWidget (i.e., as a constrained popup or as a new tab).
592//
593void RenderWidget::Show(WebWidget* webwidget,
594 WindowOpenDisposition disposition) {
595 DCHECK(!did_show_) << "received extraneous Show call";
596 DCHECK(routing_id_ != MSG_ROUTING_NONE);
597 DCHECK(opener_id_ != MSG_ROUTING_NONE);
598
599 if (!did_show_) {
600 did_show_ = true;
601 // NOTE: initial_pos_ may still have its default values at this point, but
602 // that's okay. It'll be ignored if as_popup is false, or the browser
603 // process will impose a default position otherwise.
[email protected]8085dbc82008-09-26 22:53:44604 render_thread_->Send(new ViewHostMsg_ShowWidget(
initial.commit09911bf2008-07-26 23:55:29605 opener_id_, routing_id_, initial_pos_));
606 }
607}
608
609void RenderWidget::Focus(WebWidget* webwidget) {
610 // Prevent the widget from stealing the focus if it does not have focus
611 // already. We do this by explicitely setting the focus to false again.
612 // We only let the browser focus the renderer.
613 if (!has_focus_ && webwidget_) {
614 MessageLoop::current()->PostTask(FROM_HERE,
615 NewRunnableMethod(this, &RenderWidget::ClearFocus));
616 }
617}
618
619void RenderWidget::Blur(WebWidget* webwidget) {
620 Send(new ViewHostMsg_Blur(routing_id_));
621}
622
623void RenderWidget::CloseWidgetSoon(WebWidget* webwidget) {
624 // If a page calls window.close() twice, we'll end up here twice, but that's
625 // OK. It is safe to send multiple Close messages.
626
627 // Ask the RenderWidgetHost to initiate close.
628 Send(new ViewHostMsg_Close(routing_id_));
629}
630
631void RenderWidget::Close() {
632 if (webwidget_) {
633 webwidget_->Close();
634 webwidget_ = NULL;
635 }
636}
637
[email protected]63bf66f2008-08-21 21:13:01638void RenderWidget::GetWindowRect(WebWidget* webwidget, gfx::Rect* rect) {
639 Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, rect));
initial.commit09911bf2008-07-26 23:55:29640}
641
642void RenderWidget::SetWindowRect(WebWidget* webwidget, const gfx::Rect& pos) {
643 if (did_show_) {
644 Send(new ViewHostMsg_RequestMove(routing_id_, pos));
645 } else {
646 initial_pos_ = pos;
647 }
648}
649
[email protected]d4547452008-08-28 18:36:37650void RenderWidget::GetRootWindowRect(WebWidget* webwidget, gfx::Rect* rect) {
651 Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, rect));
652}
653
initial.commit09911bf2008-07-26 23:55:29654void RenderWidget::OnImeSetInputMode(bool is_active) {
[email protected]c4bb35a2008-10-31 17:54:03655 // To prevent this renderer process from sending unnecessary IPC messages to
656 // a browser process, we permit the renderer process to send IPC messages
657 // only during the IME attached to the browser process is active.
initial.commit09911bf2008-07-26 23:55:29658 ime_is_active_ = is_active;
initial.commit09911bf2008-07-26 23:55:29659}
660
661void RenderWidget::OnImeSetComposition(int string_type,
662 int cursor_position,
663 int target_start, int target_end,
664 const std::wstring& ime_string) {
665 if (webwidget_) {
666 int string_length = static_cast<int>(ime_string.length());
667 const wchar_t* string_data = ime_string.data();
668 webwidget_->ImeSetComposition(string_type, cursor_position,
669 target_start, target_end,
670 string_length, string_data);
671 }
672}
673
[email protected]ec7dc112008-08-06 05:30:12674void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) {
675 // During shutdown we can just ignore this message.
676 if (!webwidget_)
677 return;
678
679 set_next_paint_is_repaint_ack();
680 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height());
681 DidInvalidateRect(webwidget_, repaint_rect);
682}
683
initial.commit09911bf2008-07-26 23:55:29684void RenderWidget::UpdateIME() {
685 // If a browser process does not have IMEs, its IMEs are not active, or there
686 // are not any attached widgets.
687 // a renderer process does not have to retrieve information of the focused
688 // control or send notification messages to a browser process.
689 if (!ime_is_active_) {
690 return;
691 }
692 // Retrieve the caret position from the focused widget.
693 bool enable_ime;
694 int x, y;
695 const void *id;
696 if (!webwidget_ || !webwidget_->ImeUpdateStatus(&enable_ime, &id, &x, &y)) {
697 // There are not any editable widgets attached to this process.
698 // We should disable the IME to prevent it from sending CJK strings to
699 // non-editable widgets.
700 ime_control_updated_ = true;
701 ime_control_new_state_ = false;
702 }
703 if (ime_control_updated_) {
704 // The input focus has been changed.
705 // Compare the current state with the updated state and choose actions.
706 if (ime_control_enable_ime_) {
707 if (ime_control_new_state_) {
708 // Case 1: a text input -> another text input
709 // Complete the current composition and notify the caret position.
710 enum ViewHostMsg_ImeControl control = IME_COMPLETE_COMPOSITION;
711 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), control, x, y));
712 } else {
713 // Case 2: a text input -> a password input (or a static control)
714 // Complete the current composition and disable the IME.
715 enum ViewHostMsg_ImeControl control = IME_DISABLE;
716 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), control, x, y));
717 }
718 } else {
719 if (ime_control_new_state_) {
720 // Case 3: a password input (or a static control) -> a text input
721 // Enable the IME and notify the caret position.
722 enum ViewHostMsg_ImeControl control = IME_COMPLETE_COMPOSITION;
723 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), control, x, y));
724 } else {
725 // Case 4: a password input (or a static contol) -> another password
726 // input (or another static control).
727 // The IME has been already disabled and we don't have to do anything.
728 }
729 }
730 } else {
731 // The input focus is not changed.
732 // Notify the caret position to a browser process only if it is changed.
733 if (ime_control_enable_ime_) {
734 if (x != ime_control_x_ || y != ime_control_y_) {
735 enum ViewHostMsg_ImeControl control = IME_MOVE_WINDOWS;
736 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), control, x, y));
737 }
738 }
739 }
740 // Save the updated IME status to prevent from sending the same IPC messages.
741 ime_control_updated_ = false;
742 ime_control_enable_ime_ = ime_control_new_state_;
743 ime_control_x_ = x;
744 ime_control_y_ = y;
745}
746
747void RenderWidget::DidMove(WebWidget* webwidget,
748 const WebPluginGeometry& move) {
749 size_t i = 0;
750 for (; i < plugin_window_moves_.size(); ++i) {
751 if (plugin_window_moves_[i].window == move.window) {
752 plugin_window_moves_[i] = move;
753 break;
754 }
755 }
756
757 if (i == plugin_window_moves_.size())
758 plugin_window_moves_.push_back(move);
759}