blob: c6993c155a4ac9df34f37d2ad7418e9403cfe85f [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
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"
17
18#if defined(OS_POSIX)
19#include "skia/include/SkPixelRef.h"
20#include "skia/include/SkMallocPixelRef.h"
21#endif // defined(OS_POSIX)
[email protected]8085dbc82008-09-26 22:53:4422
initial.commit09911bf2008-07-26 23:55:2923#include "webkit/glue/webinputevent.h"
24#include "webkit/glue/webwidget.h"
25
[email protected]cfd727f2009-01-09 20:21:1126RenderWidget::RenderWidget(RenderThreadBase* render_thread, bool activatable)
initial.commit09911bf2008-07-26 23:55:2927 : routing_id_(MSG_ROUTING_NONE),
[email protected]c5b3b5e2009-02-13 06:41:1128 webwidget_(NULL),
initial.commit09911bf2008-07-26 23:55:2929 opener_id_(MSG_ROUTING_NONE),
[email protected]8085dbc82008-09-26 22:53:4430 render_thread_(render_thread),
initial.commit09911bf2008-07-26 23:55:2931 host_window_(NULL),
32 current_paint_buf_(NULL),
33 current_scroll_buf_(NULL),
34 next_paint_flags_(0),
35 paint_reply_pending_(false),
36 did_show_(false),
initial.commit09911bf2008-07-26 23:55:2937 is_hidden_(false),
38 needs_repainting_on_restore_(false),
39 has_focus_(false),
[email protected]661eb9d2009-02-03 02:11:4840 closing_(false),
initial.commit09911bf2008-07-26 23:55:2941 ime_is_active_(false),
42 ime_control_enable_ime_(true),
43 ime_control_x_(-1),
44 ime_control_y_(-1),
45 ime_control_new_state_(false),
[email protected]0ebf3872008-11-07 21:35:0346 ime_control_updated_(false),
[email protected]9f23f592008-11-17 08:36:3447 ime_control_busy_(false),
[email protected]cfd727f2009-01-09 20:21:1148 activatable_(activatable) {
[email protected]8930d472009-02-21 08:05:2849 RenderProcess::current()->AddRefProcess();
[email protected]8085dbc82008-09-26 22:53:4450 DCHECK(render_thread_);
initial.commit09911bf2008-07-26 23:55:2951}
52
53RenderWidget::~RenderWidget() {
[email protected]c5b3b5e2009-02-13 06:41:1154 DCHECK(!webwidget_) << "Leaking our WebWidget!";
initial.commit09911bf2008-07-26 23:55:2955 if (current_paint_buf_) {
[email protected]8930d472009-02-21 08:05:2856 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
initial.commit09911bf2008-07-26 23:55:2957 current_paint_buf_ = NULL;
58 }
59 if (current_scroll_buf_) {
[email protected]8930d472009-02-21 08:05:2860 RenderProcess::current()->ReleaseTransportDIB(current_scroll_buf_);
initial.commit09911bf2008-07-26 23:55:2961 current_scroll_buf_ = NULL;
62 }
[email protected]8930d472009-02-21 08:05:2863 RenderProcess::current()->ReleaseProcess();
initial.commit09911bf2008-07-26 23:55:2964}
65
66/*static*/
[email protected]8085dbc82008-09-26 22:53:4467RenderWidget* RenderWidget::Create(int32 opener_id,
[email protected]0ebf3872008-11-07 21:35:0368 RenderThreadBase* render_thread,
[email protected]cfd727f2009-01-09 20:21:1169 bool activatable) {
initial.commit09911bf2008-07-26 23:55:2970 DCHECK(opener_id != MSG_ROUTING_NONE);
[email protected]0ebf3872008-11-07 21:35:0371 scoped_refptr<RenderWidget> widget = new RenderWidget(render_thread,
[email protected]cfd727f2009-01-09 20:21:1172 activatable);
initial.commit09911bf2008-07-26 23:55:2973 widget->Init(opener_id); // adds reference
74 return widget;
75}
76
77void RenderWidget::Init(int32 opener_id) {
78 DCHECK(!webwidget_);
79
80 if (opener_id != MSG_ROUTING_NONE)
81 opener_id_ = opener_id;
82
[email protected]c5b3b5e2009-02-13 06:41:1183 webwidget_ = WebWidget::Create(this);
initial.commit09911bf2008-07-26 23:55:2984
[email protected]8085dbc82008-09-26 22:53:4485 bool result = render_thread_->Send(
[email protected]cfd727f2009-01-09 20:21:1186 new ViewHostMsg_CreateWidget(opener_id, activatable_, &routing_id_));
initial.commit09911bf2008-07-26 23:55:2987 if (result) {
[email protected]8085dbc82008-09-26 22:53:4488 render_thread_->AddRoute(routing_id_, this);
initial.commit09911bf2008-07-26 23:55:2989 // Take a reference on behalf of the RenderThread. This will be balanced
90 // when we receive ViewMsg_Close.
91 AddRef();
92 } else {
93 DCHECK(false);
94 }
95}
96
97// This is used to complete pending inits and non-pending inits. For non-
98// pending cases, the parent will be the same as the current parent. This
99// indicates we do not need to reparent or anything.
[email protected]18bcc3c2009-01-27 21:39:15100void RenderWidget::CompleteInit(gfx::NativeViewId parent_hwnd) {
initial.commit09911bf2008-07-26 23:55:29101 DCHECK(routing_id_ != MSG_ROUTING_NONE);
initial.commit09911bf2008-07-26 23:55:29102
103 host_window_ = parent_hwnd;
104
105 Send(new ViewHostMsg_RendererReady(routing_id_));
106}
107
108IPC_DEFINE_MESSAGE_MAP(RenderWidget)
109 IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
110 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
111 IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize)
112 IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden)
113 IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored)
114 IPC_MESSAGE_HANDLER(ViewMsg_PaintRect_ACK, OnPaintRectAck)
115 IPC_MESSAGE_HANDLER(ViewMsg_ScrollRect_ACK, OnScrollRectAck)
116 IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent)
117 IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost)
118 IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus)
119 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetInputMode, OnImeSetInputMode)
120 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition)
[email protected]ec7dc112008-08-06 05:30:12121 IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint)
initial.commit09911bf2008-07-26 23:55:29122 IPC_MESSAGE_UNHANDLED_ERROR()
123IPC_END_MESSAGE_MAP()
124
125bool RenderWidget::Send(IPC::Message* message) {
126 // Don't send any messages after the browser has told us to close.
127 if (closing_) {
128 delete message;
129 return false;
130 }
131
132 // If given a messsage without a routing ID, then assign our routing ID.
133 if (message->routing_id() == MSG_ROUTING_NONE)
134 message->set_routing_id(routing_id_);
135
[email protected]d3fc25652009-02-24 22:31:25136 return render_thread_->Send(message);
[email protected]8085dbc82008-09-26 22:53:44137}
138
initial.commit09911bf2008-07-26 23:55:29139// Got a response from the browser after the renderer decided to create a new
140// view.
[email protected]18bcc3c2009-01-27 21:39:15141void RenderWidget::OnCreatingNewAck(gfx::NativeViewId parent) {
initial.commit09911bf2008-07-26 23:55:29142 DCHECK(routing_id_ != MSG_ROUTING_NONE);
143
144 CompleteInit(parent);
145}
146
147void RenderWidget::OnClose() {
148 if (closing_)
149 return;
150 closing_ = true;
151
152 // Browser correspondence is no longer needed at this point.
153 if (routing_id_ != MSG_ROUTING_NONE)
[email protected]8085dbc82008-09-26 22:53:44154 render_thread_->RemoveRoute(routing_id_);
initial.commit09911bf2008-07-26 23:55:29155
initial.commit09911bf2008-07-26 23:55:29156 // If there is a Send call on the stack, then it could be dangerous to close
[email protected]d3fc25652009-02-24 22:31:25157 // now. Post a task that only gets invoked when there are no nested message
158 // loops.
159 MessageLoop::current()->PostNonNestableTask(FROM_HERE,
160 NewRunnableMethod(this, &RenderWidget::Close));
161
162 // Balances the AddRef taken when we called AddRoute.
163 Release();
initial.commit09911bf2008-07-26 23:55:29164}
165
[email protected]f21c613a2009-02-12 14:46:17166void RenderWidget::OnResize(const gfx::Size& new_size,
167 const gfx::Rect& resizer_rect) {
initial.commit09911bf2008-07-26 23:55:29168 // During shutdown we can just ignore this message.
169 if (!webwidget_)
170 return;
171
[email protected]f21c613a2009-02-12 14:46:17172 // Remember the rect where the resize corner will be drawn.
173 resizer_rect_ = resizer_rect;
174
initial.commit09911bf2008-07-26 23:55:29175 // TODO(darin): We should not need to reset this here.
176 is_hidden_ = false;
177 needs_repainting_on_restore_ = false;
178
179 // We shouldn't be asked to resize to our current size.
180 DCHECK(size_ != new_size);
181 size_ = new_size;
182
183 // We should not be sent a Resize message if we have not ACK'd the previous
184 DCHECK(!next_paint_is_resize_ack());
185
186 // When resizing, we want to wait to paint before ACK'ing the resize. This
187 // ensures that we only resize as fast as we can paint. We only need to send
188 // an ACK if we are resized to a non-empty rect.
189 webwidget_->Resize(new_size);
190 if (!new_size.IsEmpty()) {
191 DCHECK(!paint_rect_.IsEmpty());
192
193 // This should have caused an invalidation of the entire view. The damaged
194 // rect could be larger than new_size if we are being made smaller.
195 DCHECK_GE(paint_rect_.width(), new_size.width());
196 DCHECK_GE(paint_rect_.height(), new_size.height());
197
198 // We will send the Resize_ACK flag once we paint again.
199 set_next_paint_is_resize_ack();
200 }
201}
202
203void RenderWidget::OnWasHidden() {
204 // Go into a mode where we stop generating paint and scrolling events.
205 is_hidden_ = true;
206}
207
208void RenderWidget::OnWasRestored(bool needs_repainting) {
209 // During shutdown we can just ignore this message.
210 if (!webwidget_)
211 return;
212
213 // See OnWasHidden
214 is_hidden_ = false;
215
216 if (!needs_repainting && !needs_repainting_on_restore_)
217 return;
218 needs_repainting_on_restore_ = false;
219
220 // Tag the next paint as a restore ack, which is picked up by DoDeferredPaint
221 // when it sends out the next PaintRect message.
222 set_next_paint_is_restore_ack();
223
224 // Generate a full repaint.
225 DidInvalidateRect(webwidget_, gfx::Rect(size_.width(), size_.height()));
226}
227
[email protected]b7fce1f2008-08-14 05:01:07228void RenderWidget::OnPaintRectAck() {
initial.commit09911bf2008-07-26 23:55:29229 DCHECK(paint_reply_pending());
230 paint_reply_pending_ = false;
[email protected]b7fce1f2008-08-14 05:01:07231 // If we sent a PaintRect message with a zero-sized bitmap, then
232 // we should have no current paint buf.
233 if (current_paint_buf_) {
[email protected]8930d472009-02-21 08:05:28234 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
[email protected]b7fce1f2008-08-14 05:01:07235 current_paint_buf_ = NULL;
initial.commit09911bf2008-07-26 23:55:29236 }
[email protected]e68e62fa2009-02-20 02:00:04237
initial.commit09911bf2008-07-26 23:55:29238 // Continue painting if necessary...
239 DoDeferredPaint();
240}
241
242void RenderWidget::OnScrollRectAck() {
243 DCHECK(scroll_reply_pending());
244
[email protected]e68e62fa2009-02-20 02:00:04245 if (current_scroll_buf_) {
[email protected]8930d472009-02-21 08:05:28246 RenderProcess::current()->ReleaseTransportDIB(current_scroll_buf_);
[email protected]e68e62fa2009-02-20 02:00:04247 current_scroll_buf_ = NULL;
248 }
initial.commit09911bf2008-07-26 23:55:29249
250 // Continue scrolling if necessary...
251 DoDeferredScroll();
252}
253
254void RenderWidget::OnHandleInputEvent(const IPC::Message& message) {
255 void* iter = NULL;
256
257 const char* data;
258 int data_length;
259 if (!message.ReadData(&iter, &data, &data_length))
260 return;
261
262 const WebInputEvent* input_event =
263 reinterpret_cast<const WebInputEvent*>(data);
264 bool processed = false;
265 if (webwidget_)
266 processed = webwidget_->HandleInputEvent(input_event);
267
268 IPC::Message* response = new ViewHostMsg_HandleInputEvent_ACK(routing_id_);
269 response->WriteInt(input_event->type);
270 if (!processed) {
271 // If the event was not processed we send it back.
272 response->WriteData(data, data_length);
273 }
274 Send(response);
275}
276
277void RenderWidget::OnMouseCaptureLost() {
278 if (webwidget_)
279 webwidget_->MouseCaptureLost();
280}
281
282void RenderWidget::OnSetFocus(bool enable) {
283 has_focus_ = enable;
284 if (webwidget_)
285 webwidget_->SetFocus(enable);
286 if (enable) {
287 // Force to retrieve the state of the focused widget to determine if we
288 // should activate IMEs next time when this process calls the UpdateIME()
289 // function.
290 ime_control_updated_ = true;
291 ime_control_new_state_ = true;
292 }
293}
294
295void RenderWidget::ClearFocus() {
296 // We may have got the focus from the browser before this gets processed, in
297 // which case we do not want to unfocus ourself.
298 if (!has_focus_ && webwidget_)
299 webwidget_->SetFocus(false);
300}
301
[email protected]176aa482008-11-14 03:25:15302void RenderWidget::PaintRect(const gfx::Rect& rect,
[email protected]661eb9d2009-02-03 02:11:48303 skia::PlatformCanvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29304 // Bring the canvas into the coordinate system of the paint rect
[email protected]661eb9d2009-02-03 02:11:48305 canvas->translate(static_cast<SkScalar>(-rect.x()),
306 static_cast<SkScalar>(-rect.y()));
initial.commit09911bf2008-07-26 23:55:29307
[email protected]661eb9d2009-02-03 02:11:48308 webwidget_->Paint(canvas, rect);
initial.commit09911bf2008-07-26 23:55:29309
310 // Flush to underlying bitmap. TODO(darin): is this needed?
[email protected]661eb9d2009-02-03 02:11:48311 canvas->getTopPlatformDevice().accessBitmap(false);
initial.commit09911bf2008-07-26 23:55:29312
313 // Let the subclass observe this paint operations.
314 DidPaint();
315}
316
initial.commit09911bf2008-07-26 23:55:29317void RenderWidget::DoDeferredPaint() {
318 if (!webwidget_ || paint_reply_pending() || paint_rect_.IsEmpty())
319 return;
320
321 // When we are hidden, we want to suppress painting, but we still need to
322 // mark this DoDeferredPaint as complete.
323 if (is_hidden_ || size_.IsEmpty()) {
324 paint_rect_ = gfx::Rect();
325 needs_repainting_on_restore_ = true;
326 return;
327 }
328
329 // Layout may generate more invalidation...
330 webwidget_->Layout();
331
332 // OK, save the current paint_rect to a local since painting may cause more
333 // invalidation. Some WebCore rendering objects only layout when painted.
334 gfx::Rect damaged_rect = paint_rect_;
335 paint_rect_ = gfx::Rect();
336
337 // Compute a buffer for painting and cache it.
[email protected]e68e62fa2009-02-20 02:00:04338 skia::PlatformCanvas* canvas =
[email protected]8930d472009-02-21 08:05:28339 RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_, damaged_rect);
[email protected]e68e62fa2009-02-20 02:00:04340 if (!canvas) {
initial.commit09911bf2008-07-26 23:55:29341 NOTREACHED();
342 return;
343 }
344
[email protected]e68e62fa2009-02-20 02:00:04345 PaintRect(damaged_rect, canvas);
initial.commit09911bf2008-07-26 23:55:29346
347 ViewHostMsg_PaintRect_Params params;
initial.commit09911bf2008-07-26 23:55:29348 params.bitmap_rect = damaged_rect;
349 params.view_size = size_;
350 params.plugin_window_moves = plugin_window_moves_;
351 params.flags = next_paint_flags_;
[email protected]e68e62fa2009-02-20 02:00:04352 params.bitmap = current_paint_buf_->id();
initial.commit09911bf2008-07-26 23:55:29353
[email protected]e68e62fa2009-02-20 02:00:04354 delete canvas;
[email protected]661eb9d2009-02-03 02:11:48355
initial.commit09911bf2008-07-26 23:55:29356 plugin_window_moves_.clear();
357
358 paint_reply_pending_ = true;
359 Send(new ViewHostMsg_PaintRect(routing_id_, params));
360 next_paint_flags_ = 0;
361
362 UpdateIME();
363}
364
365void RenderWidget::DoDeferredScroll() {
366 if (!webwidget_ || scroll_reply_pending() || scroll_rect_.IsEmpty())
367 return;
368
369 // When we are hidden, we want to suppress scrolling, but we still need to
370 // mark this DoDeferredScroll as complete.
371 if (is_hidden_ || size_.IsEmpty()) {
372 scroll_rect_ = gfx::Rect();
373 needs_repainting_on_restore_ = true;
374 return;
375 }
376
377 // Layout may generate more invalidation, so we might have to bail on
378 // optimized scrolling...
379 webwidget_->Layout();
380
381 if (scroll_rect_.IsEmpty())
382 return;
383
384 gfx::Rect damaged_rect;
385
386 // Compute the region we will expose by scrolling, and paint that into a
387 // shared memory section.
388 if (scroll_delta_.x()) {
389 int dx = scroll_delta_.x();
390 damaged_rect.set_y(scroll_rect_.y());
391 damaged_rect.set_height(scroll_rect_.height());
392 if (dx > 0) {
393 damaged_rect.set_x(scroll_rect_.x());
394 damaged_rect.set_width(dx);
395 } else {
396 damaged_rect.set_x(scroll_rect_.right() + dx);
397 damaged_rect.set_width(-dx);
398 }
399 } else {
400 int dy = scroll_delta_.y();
401 damaged_rect.set_x(scroll_rect_.x());
402 damaged_rect.set_width(scroll_rect_.width());
403 if (dy > 0) {
404 damaged_rect.set_y(scroll_rect_.y());
405 damaged_rect.set_height(dy);
406 } else {
407 damaged_rect.set_y(scroll_rect_.bottom() + dy);
408 damaged_rect.set_height(-dy);
409 }
410 }
411
412 // In case the scroll offset exceeds the width/height of the scroll rect
413 damaged_rect = scroll_rect_.Intersect(damaged_rect);
414
[email protected]e68e62fa2009-02-20 02:00:04415 skia::PlatformCanvas* canvas =
[email protected]8930d472009-02-21 08:05:28416 RenderProcess::current()->GetDrawingCanvas(&current_scroll_buf_, damaged_rect);
[email protected]e68e62fa2009-02-20 02:00:04417 if (!canvas) {
initial.commit09911bf2008-07-26 23:55:29418 NOTREACHED();
419 return;
420 }
421
422 // Set these parameters before calling Paint, since that could result in
423 // further invalidates (uncommon).
424 ViewHostMsg_ScrollRect_Params params;
initial.commit09911bf2008-07-26 23:55:29425 params.bitmap_rect = damaged_rect;
426 params.dx = scroll_delta_.x();
427 params.dy = scroll_delta_.y();
428 params.clip_rect = scroll_rect_;
429 params.view_size = size_;
430 params.plugin_window_moves = plugin_window_moves_;
[email protected]e68e62fa2009-02-20 02:00:04431 params.bitmap = current_scroll_buf_->id();
[email protected]661eb9d2009-02-03 02:11:48432
initial.commit09911bf2008-07-26 23:55:29433 plugin_window_moves_.clear();
434
435 // Mark the scroll operation as no longer pending.
436 scroll_rect_ = gfx::Rect();
437
[email protected]e68e62fa2009-02-20 02:00:04438 PaintRect(damaged_rect, canvas);
initial.commit09911bf2008-07-26 23:55:29439 Send(new ViewHostMsg_ScrollRect(routing_id_, params));
[email protected]e68e62fa2009-02-20 02:00:04440 delete canvas;
initial.commit09911bf2008-07-26 23:55:29441 UpdateIME();
442}
443
444///////////////////////////////////////////////////////////////////////////////
445// WebWidgetDelegate
446
[email protected]18bcc3c2009-01-27 21:39:15447gfx::NativeViewId RenderWidget::GetContainingView(WebWidget* webwidget) {
initial.commit09911bf2008-07-26 23:55:29448 return host_window_;
449}
450
451void RenderWidget::DidInvalidateRect(WebWidget* webwidget,
452 const gfx::Rect& rect) {
453 // We only want one pending DoDeferredPaint call at any time...
454 bool paint_pending = !paint_rect_.IsEmpty();
455
456 // If this invalidate overlaps with a pending scroll, then we have to
457 // downgrade to invalidating the scroll rect.
458 if (rect.Intersects(scroll_rect_)) {
459 paint_rect_ = paint_rect_.Union(scroll_rect_);
460 scroll_rect_ = gfx::Rect();
461 }
462
463 gfx::Rect view_rect(0, 0, size_.width(), size_.height());
464 // TODO(iyengar) Investigate why we have painting issues when
465 // we ignore invalid regions outside the view.
466 // Ignore invalidates that occur outside the bounds of the view
467 // TODO(darin): maybe this should move into the paint code?
468 // paint_rect_ = view_rect.Intersect(paint_rect_.Union(rect));
469 paint_rect_ = paint_rect_.Union(view_rect.Intersect(rect));
470
471 if (paint_rect_.IsEmpty() || paint_reply_pending() || paint_pending)
472 return;
473
474 // Perform painting asynchronously. This serves two purposes:
475 // 1) Ensures that we call WebView::Paint without a bunch of other junk
476 // on the call stack.
477 // 2) Allows us to collect more damage rects before painting to help coalesce
478 // the work that we will need to do.
479 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
480 this, &RenderWidget::DoDeferredPaint));
481}
482
483void RenderWidget::DidScrollRect(WebWidget* webwidget, int dx, int dy,
484 const gfx::Rect& clip_rect) {
485 // We only support scrolling along one axis at a time.
486 DCHECK((dx && !dy) || (!dx && dy));
487
488 bool intersects_with_painting = paint_rect_.Intersects(clip_rect);
489
490 // If we already have a pending scroll operation or if this scroll operation
491 // intersects the existing paint region, then just failover to invalidating.
492 if (!scroll_rect_.IsEmpty() || intersects_with_painting) {
493 if (!intersects_with_painting && scroll_rect_ == clip_rect) {
494 // OK, we can just update the scroll delta (requires same scrolling axis)
495 if (!dx && !scroll_delta_.x()) {
496 scroll_delta_.set_y(scroll_delta_.y() + dy);
497 return;
498 }
499 if (!dy && !scroll_delta_.y()) {
500 scroll_delta_.set_x(scroll_delta_.x() + dx);
501 return;
502 }
503 }
504 DidInvalidateRect(webwidget_, scroll_rect_);
505 DCHECK(scroll_rect_.IsEmpty());
506 DidInvalidateRect(webwidget_, clip_rect);
507 return;
508 }
509
510 // We only want one pending DoDeferredScroll call at any time...
511 bool scroll_pending = !scroll_rect_.IsEmpty();
512
513 scroll_rect_ = clip_rect;
514 scroll_delta_.SetPoint(dx, dy);
515
516 if (scroll_pending)
517 return;
518
519 // Perform scrolling asynchronously since we need to call WebView::Paint
520 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
521 this, &RenderWidget::DoDeferredScroll));
522}
523
524void RenderWidget::SetCursor(WebWidget* webwidget, const WebCursor& cursor) {
525 // Only send a SetCursor message if we need to make a change.
526 if (!current_cursor_.IsEqual(cursor)) {
527 current_cursor_ = cursor;
528 Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
529 }
530}
531
532// We are supposed to get a single call to Show for a newly created RenderWidget
533// that was created via RenderWidget::CreateWebView. So, we wait until this
534// point to dispatch the ShowWidget message.
535//
536// This method provides us with the information about how to display the newly
537// created RenderWidget (i.e., as a constrained popup or as a new tab).
538//
539void RenderWidget::Show(WebWidget* webwidget,
540 WindowOpenDisposition disposition) {
541 DCHECK(!did_show_) << "received extraneous Show call";
542 DCHECK(routing_id_ != MSG_ROUTING_NONE);
543 DCHECK(opener_id_ != MSG_ROUTING_NONE);
544
545 if (!did_show_) {
546 did_show_ = true;
547 // NOTE: initial_pos_ may still have its default values at this point, but
548 // that's okay. It'll be ignored if as_popup is false, or the browser
549 // process will impose a default position otherwise.
[email protected]8085dbc82008-09-26 22:53:44550 render_thread_->Send(new ViewHostMsg_ShowWidget(
initial.commit09911bf2008-07-26 23:55:29551 opener_id_, routing_id_, initial_pos_));
552 }
553}
554
555void RenderWidget::Focus(WebWidget* webwidget) {
556 // Prevent the widget from stealing the focus if it does not have focus
557 // already. We do this by explicitely setting the focus to false again.
558 // We only let the browser focus the renderer.
559 if (!has_focus_ && webwidget_) {
560 MessageLoop::current()->PostTask(FROM_HERE,
561 NewRunnableMethod(this, &RenderWidget::ClearFocus));
562 }
563}
564
565void RenderWidget::Blur(WebWidget* webwidget) {
566 Send(new ViewHostMsg_Blur(routing_id_));
567}
568
569void RenderWidget::CloseWidgetSoon(WebWidget* webwidget) {
570 // If a page calls window.close() twice, we'll end up here twice, but that's
571 // OK. It is safe to send multiple Close messages.
572
573 // Ask the RenderWidgetHost to initiate close.
574 Send(new ViewHostMsg_Close(routing_id_));
575}
576
577void RenderWidget::Close() {
578 if (webwidget_) {
579 webwidget_->Close();
580 webwidget_ = NULL;
581 }
582}
583
[email protected]63bf66f2008-08-21 21:13:01584void RenderWidget::GetWindowRect(WebWidget* webwidget, gfx::Rect* rect) {
585 Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, rect));
initial.commit09911bf2008-07-26 23:55:29586}
587
588void RenderWidget::SetWindowRect(WebWidget* webwidget, const gfx::Rect& pos) {
589 if (did_show_) {
590 Send(new ViewHostMsg_RequestMove(routing_id_, pos));
591 } else {
592 initial_pos_ = pos;
593 }
594}
595
[email protected]d4547452008-08-28 18:36:37596void RenderWidget::GetRootWindowRect(WebWidget* webwidget, gfx::Rect* rect) {
597 Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, rect));
598}
599
[email protected]08157312009-01-30 00:34:11600void RenderWidget::GetRootWindowResizerRect(WebWidget* webwidget,
[email protected]c04b6362008-11-21 18:54:19601 gfx::Rect* rect) {
[email protected]f21c613a2009-02-12 14:46:17602 // This is disabled to verify if WebKit is responsible for the slow down
603 // that was witnessed in the page cycler tests when the resize corner
604 // code was commited...
[email protected]fb63b722009-02-19 18:05:14605#if defined(OS_MACOSX)
606 // ...we need it enabled on Mac so scrollbars are usable.
607 *rect = resizer_rect_;
608#elif defined(OS_WIN) || defined(OS_LINUX)
[email protected]f21c613a2009-02-12 14:46:17609 *rect = gfx::Rect(); // resizer_rect_;
[email protected]fb63b722009-02-19 18:05:14610#endif
[email protected]c04b6362008-11-21 18:54:19611}
612
initial.commit09911bf2008-07-26 23:55:29613void RenderWidget::OnImeSetInputMode(bool is_active) {
[email protected]c4bb35a2008-10-31 17:54:03614 // To prevent this renderer process from sending unnecessary IPC messages to
615 // a browser process, we permit the renderer process to send IPC messages
616 // only during the IME attached to the browser process is active.
initial.commit09911bf2008-07-26 23:55:29617 ime_is_active_ = is_active;
initial.commit09911bf2008-07-26 23:55:29618}
619
620void RenderWidget::OnImeSetComposition(int string_type,
621 int cursor_position,
622 int target_start, int target_end,
623 const std::wstring& ime_string) {
624 if (webwidget_) {
[email protected]9f23f592008-11-17 08:36:34625 ime_control_busy_ = true;
initial.commit09911bf2008-07-26 23:55:29626 webwidget_->ImeSetComposition(string_type, cursor_position,
627 target_start, target_end,
[email protected]34f6bc12008-11-06 07:40:53628 ime_string);
[email protected]9f23f592008-11-17 08:36:34629 ime_control_busy_ = false;
initial.commit09911bf2008-07-26 23:55:29630 }
631}
632
[email protected]ec7dc112008-08-06 05:30:12633void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) {
634 // During shutdown we can just ignore this message.
635 if (!webwidget_)
636 return;
637
638 set_next_paint_is_repaint_ack();
639 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height());
640 DidInvalidateRect(webwidget_, repaint_rect);
641}
642
[email protected]674741932009-02-04 23:44:46643bool RenderWidget::next_paint_is_resize_ack() const {
644 return ViewHostMsg_PaintRect_Flags::is_resize_ack(next_paint_flags_);
645}
646
647bool RenderWidget::next_paint_is_restore_ack() const {
648 return ViewHostMsg_PaintRect_Flags::is_restore_ack(next_paint_flags_);
649}
650
651void RenderWidget::set_next_paint_is_resize_ack() {
652 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESIZE_ACK;
653}
654
655void RenderWidget::set_next_paint_is_restore_ack() {
656 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESTORE_ACK;
657}
658
659void RenderWidget::set_next_paint_is_repaint_ack() {
660 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_REPAINT_ACK;
661}
662
initial.commit09911bf2008-07-26 23:55:29663void RenderWidget::UpdateIME() {
664 // If a browser process does not have IMEs, its IMEs are not active, or there
665 // are not any attached widgets.
666 // a renderer process does not have to retrieve information of the focused
667 // control or send notification messages to a browser process.
668 if (!ime_is_active_) {
669 return;
670 }
[email protected]34f6bc12008-11-06 07:40:53671 // Retrieve the caret position from the focused widget and verify we should
672 // enabled IMEs attached to the browser process.
673 bool enable_ime = false;
[email protected]34f6bc12008-11-06 07:40:53674 gfx::Rect caret_rect;
675 if (!webwidget_ ||
[email protected]8dcfd8c92009-02-20 16:15:12676 !webwidget_->ImeUpdateStatus(&enable_ime, &caret_rect)) {
initial.commit09911bf2008-07-26 23:55:29677 // There are not any editable widgets attached to this process.
678 // We should disable the IME to prevent it from sending CJK strings to
679 // non-editable widgets.
680 ime_control_updated_ = true;
681 ime_control_new_state_ = false;
682 }
[email protected]9f23f592008-11-17 08:36:34683 if (ime_control_new_state_ != enable_ime) {
684 ime_control_updated_ = true;
685 ime_control_new_state_ = enable_ime;
686 }
initial.commit09911bf2008-07-26 23:55:29687 if (ime_control_updated_) {
688 // The input focus has been changed.
689 // Compare the current state with the updated state and choose actions.
690 if (ime_control_enable_ime_) {
691 if (ime_control_new_state_) {
692 // Case 1: a text input -> another text input
693 // Complete the current composition and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53694 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
695 IME_COMPLETE_COMPOSITION,
696 caret_rect));
initial.commit09911bf2008-07-26 23:55:29697 } else {
698 // Case 2: a text input -> a password input (or a static control)
699 // Complete the current composition and disable the IME.
[email protected]34f6bc12008-11-06 07:40:53700 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_DISABLE,
701 caret_rect));
initial.commit09911bf2008-07-26 23:55:29702 }
703 } else {
704 if (ime_control_new_state_) {
705 // Case 3: a password input (or a static control) -> a text input
706 // Enable the IME and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53707 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
708 IME_COMPLETE_COMPOSITION,
709 caret_rect));
initial.commit09911bf2008-07-26 23:55:29710 } else {
711 // Case 4: a password input (or a static contol) -> another password
712 // input (or another static control).
713 // The IME has been already disabled and we don't have to do anything.
714 }
715 }
716 } else {
717 // The input focus is not changed.
718 // Notify the caret position to a browser process only if it is changed.
719 if (ime_control_enable_ime_) {
[email protected]34f6bc12008-11-06 07:40:53720 if (caret_rect.x() != ime_control_x_ ||
721 caret_rect.y() != ime_control_y_) {
722 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_MOVE_WINDOWS,
723 caret_rect));
initial.commit09911bf2008-07-26 23:55:29724 }
725 }
726 }
727 // Save the updated IME status to prevent from sending the same IPC messages.
728 ime_control_updated_ = false;
729 ime_control_enable_ime_ = ime_control_new_state_;
[email protected]34f6bc12008-11-06 07:40:53730 ime_control_x_ = caret_rect.x();
731 ime_control_y_ = caret_rect.y();
initial.commit09911bf2008-07-26 23:55:29732}
733
734void RenderWidget::DidMove(WebWidget* webwidget,
735 const WebPluginGeometry& move) {
736 size_t i = 0;
737 for (; i < plugin_window_moves_.size(); ++i) {
738 if (plugin_window_moves_[i].window == move.window) {
739 plugin_window_moves_[i] = move;
740 break;
741 }
742 }
743
744 if (i == plugin_window_moves_.size())
745 plugin_window_moves_.push_back(move);
746}