blob: ab1a270ec93b91cb953e8a75a6cc87d1afe94f1c [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]0ebf3872008-11-07 21:35:0372RenderWidget::RenderWidget(RenderThreadBase* render_thread,
73 bool focus_on_show)
initial.commit09911bf2008-07-26 23:55:2974 : routing_id_(MSG_ROUTING_NONE),
75 opener_id_(MSG_ROUTING_NONE),
[email protected]8085dbc82008-09-26 22:53:4476 render_thread_(render_thread),
initial.commit09911bf2008-07-26 23:55:2977 host_window_(NULL),
78 current_paint_buf_(NULL),
79 current_scroll_buf_(NULL),
80 next_paint_flags_(0),
81 paint_reply_pending_(false),
82 did_show_(false),
83 closing_(false),
84 is_hidden_(false),
85 needs_repainting_on_restore_(false),
86 has_focus_(false),
87 ime_is_active_(false),
88 ime_control_enable_ime_(true),
89 ime_control_x_(-1),
90 ime_control_y_(-1),
91 ime_control_new_state_(false),
[email protected]0ebf3872008-11-07 21:35:0392 ime_control_updated_(false),
93 focus_on_show_(focus_on_show) {
initial.commit09911bf2008-07-26 23:55:2994 RenderProcess::AddRefProcess();
[email protected]8085dbc82008-09-26 22:53:4495 DCHECK(render_thread_);
initial.commit09911bf2008-07-26 23:55:2996}
97
98RenderWidget::~RenderWidget() {
99 if (current_paint_buf_) {
100 RenderProcess::FreeSharedMemory(current_paint_buf_);
101 current_paint_buf_ = NULL;
102 }
103 if (current_scroll_buf_) {
104 RenderProcess::FreeSharedMemory(current_scroll_buf_);
105 current_scroll_buf_ = NULL;
106 }
107 RenderProcess::ReleaseProcess();
108}
109
110/*static*/
[email protected]8085dbc82008-09-26 22:53:44111RenderWidget* RenderWidget::Create(int32 opener_id,
[email protected]0ebf3872008-11-07 21:35:03112 RenderThreadBase* render_thread,
113 bool focus_on_show) {
initial.commit09911bf2008-07-26 23:55:29114 DCHECK(opener_id != MSG_ROUTING_NONE);
[email protected]0ebf3872008-11-07 21:35:03115 scoped_refptr<RenderWidget> widget = new RenderWidget(render_thread,
116 focus_on_show);
initial.commit09911bf2008-07-26 23:55:29117 widget->Init(opener_id); // adds reference
118 return widget;
119}
120
121void RenderWidget::Init(int32 opener_id) {
122 DCHECK(!webwidget_);
123
124 if (opener_id != MSG_ROUTING_NONE)
125 opener_id_ = opener_id;
126
127 // Avoid a leak here by not assigning, since WebWidget::Create addrefs for us.
128 WebWidget* webwidget = WebWidget::Create(this);
129 webwidget_.swap(&webwidget);
130
[email protected]8085dbc82008-09-26 22:53:44131 bool result = render_thread_->Send(
[email protected]0ebf3872008-11-07 21:35:03132 new ViewHostMsg_CreateWidget(opener_id, focus_on_show_, &routing_id_));
initial.commit09911bf2008-07-26 23:55:29133 if (result) {
[email protected]8085dbc82008-09-26 22:53:44134 render_thread_->AddRoute(routing_id_, this);
initial.commit09911bf2008-07-26 23:55:29135 // Take a reference on behalf of the RenderThread. This will be balanced
136 // when we receive ViewMsg_Close.
137 AddRef();
138 } else {
139 DCHECK(false);
140 }
141}
142
143// This is used to complete pending inits and non-pending inits. For non-
144// pending cases, the parent will be the same as the current parent. This
145// indicates we do not need to reparent or anything.
146void RenderWidget::CompleteInit(HWND parent_hwnd) {
147 DCHECK(routing_id_ != MSG_ROUTING_NONE);
148 DCHECK(parent_hwnd);
149
150 host_window_ = parent_hwnd;
151
152 Send(new ViewHostMsg_RendererReady(routing_id_));
153}
154
155IPC_DEFINE_MESSAGE_MAP(RenderWidget)
156 IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
157 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
158 IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize)
159 IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden)
160 IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored)
161 IPC_MESSAGE_HANDLER(ViewMsg_PaintRect_ACK, OnPaintRectAck)
162 IPC_MESSAGE_HANDLER(ViewMsg_ScrollRect_ACK, OnScrollRectAck)
163 IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent)
164 IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost)
165 IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus)
166 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetInputMode, OnImeSetInputMode)
167 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition)
[email protected]ec7dc112008-08-06 05:30:12168 IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint)
initial.commit09911bf2008-07-26 23:55:29169 IPC_MESSAGE_UNHANDLED_ERROR()
170IPC_END_MESSAGE_MAP()
171
172bool RenderWidget::Send(IPC::Message* message) {
173 // Don't send any messages after the browser has told us to close.
174 if (closing_) {
175 delete message;
176 return false;
177 }
178
179 // If given a messsage without a routing ID, then assign our routing ID.
180 if (message->routing_id() == MSG_ROUTING_NONE)
181 message->set_routing_id(routing_id_);
182
[email protected]8085dbc82008-09-26 22:53:44183 bool rv = render_thread_->Send(message);
initial.commit09911bf2008-07-26 23:55:29184
185 // If there aren't any more RenderThread::Send calls on the stack, then we
186 // can go ahead and schedule Close to be called on any RenderWidget objects
187 // that received a ViewMsg_Close while we were inside Send.
[email protected]8085dbc82008-09-26 22:53:44188 if (!render_thread_->InSend())
initial.commit09911bf2008-07-26 23:55:29189 DeferredCloses::Post();
190
191 return rv;
192}
193
[email protected]8085dbc82008-09-26 22:53:44194bool RenderWidget::InSend() const {
195 return render_thread_->InSend();
196}
197
initial.commit09911bf2008-07-26 23:55:29198// Got a response from the browser after the renderer decided to create a new
199// view.
200void RenderWidget::OnCreatingNewAck(HWND parent) {
201 DCHECK(routing_id_ != MSG_ROUTING_NONE);
202
203 CompleteInit(parent);
204}
205
206void RenderWidget::OnClose() {
207 if (closing_)
208 return;
209 closing_ = true;
210
211 // Browser correspondence is no longer needed at this point.
212 if (routing_id_ != MSG_ROUTING_NONE)
[email protected]8085dbc82008-09-26 22:53:44213 render_thread_->RemoveRoute(routing_id_);
initial.commit09911bf2008-07-26 23:55:29214
215 // Balances the AddRef taken when we called AddRoute. This release happens
216 // via the MessageLoop since it may cause our destruction.
217 MessageLoop::current()->ReleaseSoon(FROM_HERE, this);
218
219 // If there is a Send call on the stack, then it could be dangerous to close
220 // now. Instead, we wait until we get out of Send.
[email protected]8085dbc82008-09-26 22:53:44221 if (render_thread_->InSend()) {
initial.commit09911bf2008-07-26 23:55:29222 DeferredCloses::Push(this);
223 } else {
224 Close();
225 }
226}
227
228void RenderWidget::OnResize(const gfx::Size& new_size) {
229 // During shutdown we can just ignore this message.
230 if (!webwidget_)
231 return;
232
233 // TODO(darin): We should not need to reset this here.
234 is_hidden_ = false;
235 needs_repainting_on_restore_ = false;
236
237 // We shouldn't be asked to resize to our current size.
238 DCHECK(size_ != new_size);
239 size_ = new_size;
240
241 // We should not be sent a Resize message if we have not ACK'd the previous
242 DCHECK(!next_paint_is_resize_ack());
243
244 // When resizing, we want to wait to paint before ACK'ing the resize. This
245 // ensures that we only resize as fast as we can paint. We only need to send
246 // an ACK if we are resized to a non-empty rect.
247 webwidget_->Resize(new_size);
248 if (!new_size.IsEmpty()) {
249 DCHECK(!paint_rect_.IsEmpty());
250
251 // This should have caused an invalidation of the entire view. The damaged
252 // rect could be larger than new_size if we are being made smaller.
253 DCHECK_GE(paint_rect_.width(), new_size.width());
254 DCHECK_GE(paint_rect_.height(), new_size.height());
255
256 // We will send the Resize_ACK flag once we paint again.
257 set_next_paint_is_resize_ack();
258 }
259}
260
261void RenderWidget::OnWasHidden() {
262 // Go into a mode where we stop generating paint and scrolling events.
263 is_hidden_ = true;
264}
265
266void RenderWidget::OnWasRestored(bool needs_repainting) {
267 // During shutdown we can just ignore this message.
268 if (!webwidget_)
269 return;
270
271 // See OnWasHidden
272 is_hidden_ = false;
273
274 if (!needs_repainting && !needs_repainting_on_restore_)
275 return;
276 needs_repainting_on_restore_ = false;
277
278 // Tag the next paint as a restore ack, which is picked up by DoDeferredPaint
279 // when it sends out the next PaintRect message.
280 set_next_paint_is_restore_ack();
281
282 // Generate a full repaint.
283 DidInvalidateRect(webwidget_, gfx::Rect(size_.width(), size_.height()));
284}
285
[email protected]b7fce1f2008-08-14 05:01:07286void RenderWidget::OnPaintRectAck() {
initial.commit09911bf2008-07-26 23:55:29287 DCHECK(paint_reply_pending());
288 paint_reply_pending_ = false;
[email protected]b7fce1f2008-08-14 05:01:07289 // If we sent a PaintRect message with a zero-sized bitmap, then
290 // we should have no current paint buf.
291 if (current_paint_buf_) {
292 RenderProcess::FreeSharedMemory(current_paint_buf_);
293 current_paint_buf_ = NULL;
initial.commit09911bf2008-07-26 23:55:29294 }
initial.commit09911bf2008-07-26 23:55:29295 // Continue painting if necessary...
296 DoDeferredPaint();
297}
298
299void RenderWidget::OnScrollRectAck() {
300 DCHECK(scroll_reply_pending());
301
302 RenderProcess::FreeSharedMemory(current_scroll_buf_);
303 current_scroll_buf_ = NULL;
304
305 // Continue scrolling if necessary...
306 DoDeferredScroll();
307}
308
309void RenderWidget::OnHandleInputEvent(const IPC::Message& message) {
310 void* iter = NULL;
311
312 const char* data;
313 int data_length;
314 if (!message.ReadData(&iter, &data, &data_length))
315 return;
316
317 const WebInputEvent* input_event =
318 reinterpret_cast<const WebInputEvent*>(data);
319 bool processed = false;
320 if (webwidget_)
321 processed = webwidget_->HandleInputEvent(input_event);
322
323 IPC::Message* response = new ViewHostMsg_HandleInputEvent_ACK(routing_id_);
324 response->WriteInt(input_event->type);
325 if (!processed) {
326 // If the event was not processed we send it back.
327 response->WriteData(data, data_length);
328 }
329 Send(response);
330}
331
332void RenderWidget::OnMouseCaptureLost() {
333 if (webwidget_)
334 webwidget_->MouseCaptureLost();
335}
336
337void RenderWidget::OnSetFocus(bool enable) {
338 has_focus_ = enable;
339 if (webwidget_)
340 webwidget_->SetFocus(enable);
341 if (enable) {
342 // Force to retrieve the state of the focused widget to determine if we
343 // should activate IMEs next time when this process calls the UpdateIME()
344 // function.
345 ime_control_updated_ = true;
346 ime_control_new_state_ = true;
347 }
348}
349
350void RenderWidget::ClearFocus() {
351 // We may have got the focus from the browser before this gets processed, in
352 // which case we do not want to unfocus ourself.
353 if (!has_focus_ && webwidget_)
354 webwidget_->SetFocus(false);
355}
356
357void RenderWidget::PaintRect(const gfx::Rect& rect, SharedMemory* paint_buf) {
[email protected]b49cbcf22008-08-14 17:47:00358 gfx::PlatformCanvasWin canvas(rect.width(), rect.height(), true,
initial.commit09911bf2008-07-26 23:55:29359 paint_buf->handle());
360 // Bring the canvas into the coordinate system of the paint rect
361 canvas.translate(static_cast<SkScalar>(-rect.x()),
362 static_cast<SkScalar>(-rect.y()));
363
364 webwidget_->Paint(&canvas, rect);
365
366 // Flush to underlying bitmap. TODO(darin): is this needed?
367 canvas.getTopPlatformDevice().accessBitmap(false);
368
369 // Let the subclass observe this paint operations.
370 DidPaint();
371}
372
373size_t RenderWidget::GetPaintBufSize(const gfx::Rect& rect) {
374 // TODO(darin): protect against overflow
375 return 4 * rect.width() * rect.height();
376}
377
378void RenderWidget::DoDeferredPaint() {
379 if (!webwidget_ || paint_reply_pending() || paint_rect_.IsEmpty())
380 return;
381
382 // When we are hidden, we want to suppress painting, but we still need to
383 // mark this DoDeferredPaint as complete.
384 if (is_hidden_ || size_.IsEmpty()) {
385 paint_rect_ = gfx::Rect();
386 needs_repainting_on_restore_ = true;
387 return;
388 }
389
390 // Layout may generate more invalidation...
391 webwidget_->Layout();
392
393 // OK, save the current paint_rect to a local since painting may cause more
394 // invalidation. Some WebCore rendering objects only layout when painted.
395 gfx::Rect damaged_rect = paint_rect_;
396 paint_rect_ = gfx::Rect();
397
398 // Compute a buffer for painting and cache it.
399 current_paint_buf_ =
400 RenderProcess::AllocSharedMemory(GetPaintBufSize(damaged_rect));
401 if (!current_paint_buf_) {
402 NOTREACHED();
403 return;
404 }
405
406 PaintRect(damaged_rect, current_paint_buf_);
407
408 ViewHostMsg_PaintRect_Params params;
409 params.bitmap = current_paint_buf_->handle();
410 params.bitmap_rect = damaged_rect;
411 params.view_size = size_;
412 params.plugin_window_moves = plugin_window_moves_;
413 params.flags = next_paint_flags_;
414
415 plugin_window_moves_.clear();
416
417 paint_reply_pending_ = true;
418 Send(new ViewHostMsg_PaintRect(routing_id_, params));
419 next_paint_flags_ = 0;
420
421 UpdateIME();
422}
423
424void RenderWidget::DoDeferredScroll() {
425 if (!webwidget_ || scroll_reply_pending() || scroll_rect_.IsEmpty())
426 return;
427
428 // When we are hidden, we want to suppress scrolling, but we still need to
429 // mark this DoDeferredScroll as complete.
430 if (is_hidden_ || size_.IsEmpty()) {
431 scroll_rect_ = gfx::Rect();
432 needs_repainting_on_restore_ = true;
433 return;
434 }
435
436 // Layout may generate more invalidation, so we might have to bail on
437 // optimized scrolling...
438 webwidget_->Layout();
439
440 if (scroll_rect_.IsEmpty())
441 return;
442
443 gfx::Rect damaged_rect;
444
445 // Compute the region we will expose by scrolling, and paint that into a
446 // shared memory section.
447 if (scroll_delta_.x()) {
448 int dx = scroll_delta_.x();
449 damaged_rect.set_y(scroll_rect_.y());
450 damaged_rect.set_height(scroll_rect_.height());
451 if (dx > 0) {
452 damaged_rect.set_x(scroll_rect_.x());
453 damaged_rect.set_width(dx);
454 } else {
455 damaged_rect.set_x(scroll_rect_.right() + dx);
456 damaged_rect.set_width(-dx);
457 }
458 } else {
459 int dy = scroll_delta_.y();
460 damaged_rect.set_x(scroll_rect_.x());
461 damaged_rect.set_width(scroll_rect_.width());
462 if (dy > 0) {
463 damaged_rect.set_y(scroll_rect_.y());
464 damaged_rect.set_height(dy);
465 } else {
466 damaged_rect.set_y(scroll_rect_.bottom() + dy);
467 damaged_rect.set_height(-dy);
468 }
469 }
470
471 // In case the scroll offset exceeds the width/height of the scroll rect
472 damaged_rect = scroll_rect_.Intersect(damaged_rect);
473
474 current_scroll_buf_ =
475 RenderProcess::AllocSharedMemory(GetPaintBufSize(damaged_rect));
476 if (!current_scroll_buf_) {
477 NOTREACHED();
478 return;
479 }
480
481 // Set these parameters before calling Paint, since that could result in
482 // further invalidates (uncommon).
483 ViewHostMsg_ScrollRect_Params params;
484 params.bitmap = current_scroll_buf_->handle();
485 params.bitmap_rect = damaged_rect;
486 params.dx = scroll_delta_.x();
487 params.dy = scroll_delta_.y();
488 params.clip_rect = scroll_rect_;
489 params.view_size = size_;
490 params.plugin_window_moves = plugin_window_moves_;
491
492 plugin_window_moves_.clear();
493
494 // Mark the scroll operation as no longer pending.
495 scroll_rect_ = gfx::Rect();
496
497 PaintRect(damaged_rect, current_scroll_buf_);
498 Send(new ViewHostMsg_ScrollRect(routing_id_, params));
499 UpdateIME();
500}
501
502///////////////////////////////////////////////////////////////////////////////
503// WebWidgetDelegate
504
505HWND RenderWidget::GetContainingWindow(WebWidget* webwidget) {
506 return host_window_;
507}
508
509void RenderWidget::DidInvalidateRect(WebWidget* webwidget,
510 const gfx::Rect& rect) {
511 // We only want one pending DoDeferredPaint call at any time...
512 bool paint_pending = !paint_rect_.IsEmpty();
513
514 // If this invalidate overlaps with a pending scroll, then we have to
515 // downgrade to invalidating the scroll rect.
516 if (rect.Intersects(scroll_rect_)) {
517 paint_rect_ = paint_rect_.Union(scroll_rect_);
518 scroll_rect_ = gfx::Rect();
519 }
520
521 gfx::Rect view_rect(0, 0, size_.width(), size_.height());
522 // TODO(iyengar) Investigate why we have painting issues when
523 // we ignore invalid regions outside the view.
524 // Ignore invalidates that occur outside the bounds of the view
525 // TODO(darin): maybe this should move into the paint code?
526 // paint_rect_ = view_rect.Intersect(paint_rect_.Union(rect));
527 paint_rect_ = paint_rect_.Union(view_rect.Intersect(rect));
528
529 if (paint_rect_.IsEmpty() || paint_reply_pending() || paint_pending)
530 return;
531
532 // Perform painting asynchronously. This serves two purposes:
533 // 1) Ensures that we call WebView::Paint without a bunch of other junk
534 // on the call stack.
535 // 2) Allows us to collect more damage rects before painting to help coalesce
536 // the work that we will need to do.
537 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
538 this, &RenderWidget::DoDeferredPaint));
539}
540
541void RenderWidget::DidScrollRect(WebWidget* webwidget, int dx, int dy,
542 const gfx::Rect& clip_rect) {
543 // We only support scrolling along one axis at a time.
544 DCHECK((dx && !dy) || (!dx && dy));
545
546 bool intersects_with_painting = paint_rect_.Intersects(clip_rect);
547
548 // If we already have a pending scroll operation or if this scroll operation
549 // intersects the existing paint region, then just failover to invalidating.
550 if (!scroll_rect_.IsEmpty() || intersects_with_painting) {
551 if (!intersects_with_painting && scroll_rect_ == clip_rect) {
552 // OK, we can just update the scroll delta (requires same scrolling axis)
553 if (!dx && !scroll_delta_.x()) {
554 scroll_delta_.set_y(scroll_delta_.y() + dy);
555 return;
556 }
557 if (!dy && !scroll_delta_.y()) {
558 scroll_delta_.set_x(scroll_delta_.x() + dx);
559 return;
560 }
561 }
562 DidInvalidateRect(webwidget_, scroll_rect_);
563 DCHECK(scroll_rect_.IsEmpty());
564 DidInvalidateRect(webwidget_, clip_rect);
565 return;
566 }
567
568 // We only want one pending DoDeferredScroll call at any time...
569 bool scroll_pending = !scroll_rect_.IsEmpty();
570
571 scroll_rect_ = clip_rect;
572 scroll_delta_.SetPoint(dx, dy);
573
574 if (scroll_pending)
575 return;
576
577 // Perform scrolling asynchronously since we need to call WebView::Paint
578 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
579 this, &RenderWidget::DoDeferredScroll));
580}
581
582void RenderWidget::SetCursor(WebWidget* webwidget, const WebCursor& cursor) {
583 // Only send a SetCursor message if we need to make a change.
584 if (!current_cursor_.IsEqual(cursor)) {
585 current_cursor_ = cursor;
586 Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
587 }
588}
589
590// We are supposed to get a single call to Show for a newly created RenderWidget
591// that was created via RenderWidget::CreateWebView. So, we wait until this
592// point to dispatch the ShowWidget message.
593//
594// This method provides us with the information about how to display the newly
595// created RenderWidget (i.e., as a constrained popup or as a new tab).
596//
597void RenderWidget::Show(WebWidget* webwidget,
598 WindowOpenDisposition disposition) {
599 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]8085dbc82008-09-26 22:53:44608 render_thread_->Send(new ViewHostMsg_ShowWidget(
initial.commit09911bf2008-07-26 23:55:29609 opener_id_, routing_id_, initial_pos_));
610 }
611}
612
613void RenderWidget::Focus(WebWidget* webwidget) {
614 // Prevent the widget from stealing the focus if it does not have focus
615 // already. We do this by explicitely setting the focus to false again.
616 // We only let the browser focus the renderer.
617 if (!has_focus_ && webwidget_) {
618 MessageLoop::current()->PostTask(FROM_HERE,
619 NewRunnableMethod(this, &RenderWidget::ClearFocus));
620 }
621}
622
623void RenderWidget::Blur(WebWidget* webwidget) {
624 Send(new ViewHostMsg_Blur(routing_id_));
625}
626
627void RenderWidget::CloseWidgetSoon(WebWidget* webwidget) {
628 // If a page calls window.close() twice, we'll end up here twice, but that's
629 // OK. It is safe to send multiple Close messages.
630
631 // Ask the RenderWidgetHost to initiate close.
632 Send(new ViewHostMsg_Close(routing_id_));
633}
634
635void RenderWidget::Close() {
636 if (webwidget_) {
637 webwidget_->Close();
638 webwidget_ = NULL;
639 }
640}
641
[email protected]63bf66f2008-08-21 21:13:01642void RenderWidget::GetWindowRect(WebWidget* webwidget, gfx::Rect* rect) {
643 Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, rect));
initial.commit09911bf2008-07-26 23:55:29644}
645
646void RenderWidget::SetWindowRect(WebWidget* webwidget, const gfx::Rect& pos) {
647 if (did_show_) {
648 Send(new ViewHostMsg_RequestMove(routing_id_, pos));
649 } else {
650 initial_pos_ = pos;
651 }
652}
653
[email protected]d4547452008-08-28 18:36:37654void RenderWidget::GetRootWindowRect(WebWidget* webwidget, gfx::Rect* rect) {
655 Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, rect));
656}
657
initial.commit09911bf2008-07-26 23:55:29658void RenderWidget::OnImeSetInputMode(bool is_active) {
[email protected]c4bb35a2008-10-31 17:54:03659 // To prevent this renderer process from sending unnecessary IPC messages to
660 // a browser process, we permit the renderer process to send IPC messages
661 // only during the IME attached to the browser process is active.
initial.commit09911bf2008-07-26 23:55:29662 ime_is_active_ = is_active;
initial.commit09911bf2008-07-26 23:55:29663}
664
665void RenderWidget::OnImeSetComposition(int string_type,
666 int cursor_position,
667 int target_start, int target_end,
668 const std::wstring& ime_string) {
669 if (webwidget_) {
initial.commit09911bf2008-07-26 23:55:29670 webwidget_->ImeSetComposition(string_type, cursor_position,
671 target_start, target_end,
[email protected]34f6bc12008-11-06 07:40:53672 ime_string);
initial.commit09911bf2008-07-26 23:55:29673 }
674}
675
[email protected]ec7dc112008-08-06 05:30:12676void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) {
677 // During shutdown we can just ignore this message.
678 if (!webwidget_)
679 return;
680
681 set_next_paint_is_repaint_ack();
682 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height());
683 DidInvalidateRect(webwidget_, repaint_rect);
684}
685
initial.commit09911bf2008-07-26 23:55:29686void RenderWidget::UpdateIME() {
687 // If a browser process does not have IMEs, its IMEs are not active, or there
688 // are not any attached widgets.
689 // a renderer process does not have to retrieve information of the focused
690 // control or send notification messages to a browser process.
691 if (!ime_is_active_) {
692 return;
693 }
[email protected]34f6bc12008-11-06 07:40:53694 // Retrieve the caret position from the focused widget and verify we should
695 // enabled IMEs attached to the browser process.
696 bool enable_ime = false;
697 const void* node = NULL;
698 gfx::Rect caret_rect;
699 if (!webwidget_ ||
700 !webwidget_->ImeUpdateStatus(&enable_ime, &node, &caret_rect)) {
initial.commit09911bf2008-07-26 23:55:29701 // There are not any editable widgets attached to this process.
702 // We should disable the IME to prevent it from sending CJK strings to
703 // non-editable widgets.
704 ime_control_updated_ = true;
705 ime_control_new_state_ = false;
706 }
[email protected]34f6bc12008-11-06 07:40:53707 ime_control_new_state_ = enable_ime;
initial.commit09911bf2008-07-26 23:55:29708 if (ime_control_updated_) {
709 // The input focus has been changed.
710 // Compare the current state with the updated state and choose actions.
711 if (ime_control_enable_ime_) {
712 if (ime_control_new_state_) {
713 // Case 1: a text input -> another text input
714 // Complete the current composition and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53715 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
716 IME_COMPLETE_COMPOSITION,
717 caret_rect));
initial.commit09911bf2008-07-26 23:55:29718 } else {
719 // Case 2: a text input -> a password input (or a static control)
720 // Complete the current composition and disable the IME.
[email protected]34f6bc12008-11-06 07:40:53721 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_DISABLE,
722 caret_rect));
initial.commit09911bf2008-07-26 23:55:29723 }
724 } else {
725 if (ime_control_new_state_) {
726 // Case 3: a password input (or a static control) -> a text input
727 // Enable the IME and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53728 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
729 IME_COMPLETE_COMPOSITION,
730 caret_rect));
initial.commit09911bf2008-07-26 23:55:29731 } else {
732 // Case 4: a password input (or a static contol) -> another password
733 // input (or another static control).
734 // The IME has been already disabled and we don't have to do anything.
735 }
736 }
737 } else {
738 // The input focus is not changed.
739 // Notify the caret position to a browser process only if it is changed.
740 if (ime_control_enable_ime_) {
[email protected]34f6bc12008-11-06 07:40:53741 if (caret_rect.x() != ime_control_x_ ||
742 caret_rect.y() != ime_control_y_) {
743 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_MOVE_WINDOWS,
744 caret_rect));
initial.commit09911bf2008-07-26 23:55:29745 }
746 }
747 }
748 // Save the updated IME status to prevent from sending the same IPC messages.
749 ime_control_updated_ = false;
750 ime_control_enable_ime_ = ime_control_new_state_;
[email protected]34f6bc12008-11-06 07:40:53751 ime_control_x_ = caret_rect.x();
752 ime_control_y_ = caret_rect.y();
initial.commit09911bf2008-07-26 23:55:29753}
754
755void RenderWidget::DidMove(WebWidget* webwidget,
756 const WebPluginGeometry& move) {
757 size_t i = 0;
758 for (; i < plugin_window_moves_.size(); ++i) {
759 if (plugin_window_moves_[i].window == move.window) {
760 plugin_window_moves_[i] = move;
761 break;
762 }
763 }
764
765 if (i == plugin_window_moves_.size())
766 plugin_window_moves_.push_back(move);
767}