blob: a7ad380ee157f51955f3bbdeb6ab9923dd6b09b3 [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
[email protected]6de74452009-02-25 18:04:59105 Send(new ViewHostMsg_RenderViewReady(routing_id_));
initial.commit09911bf2008-07-26 23:55:29106}
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);
[email protected]e2824412009-02-27 01:57:05270 response->WriteBool(processed);
271
initial.commit09911bf2008-07-26 23:55:29272 Send(response);
273}
274
275void RenderWidget::OnMouseCaptureLost() {
276 if (webwidget_)
277 webwidget_->MouseCaptureLost();
278}
279
280void RenderWidget::OnSetFocus(bool enable) {
281 has_focus_ = enable;
282 if (webwidget_)
283 webwidget_->SetFocus(enable);
284 if (enable) {
285 // Force to retrieve the state of the focused widget to determine if we
286 // should activate IMEs next time when this process calls the UpdateIME()
287 // function.
288 ime_control_updated_ = true;
289 ime_control_new_state_ = true;
290 }
291}
292
293void RenderWidget::ClearFocus() {
294 // We may have got the focus from the browser before this gets processed, in
295 // which case we do not want to unfocus ourself.
296 if (!has_focus_ && webwidget_)
297 webwidget_->SetFocus(false);
298}
299
[email protected]176aa482008-11-14 03:25:15300void RenderWidget::PaintRect(const gfx::Rect& rect,
[email protected]661eb9d2009-02-03 02:11:48301 skia::PlatformCanvas* canvas) {
initial.commit09911bf2008-07-26 23:55:29302 // Bring the canvas into the coordinate system of the paint rect
[email protected]661eb9d2009-02-03 02:11:48303 canvas->translate(static_cast<SkScalar>(-rect.x()),
304 static_cast<SkScalar>(-rect.y()));
initial.commit09911bf2008-07-26 23:55:29305
[email protected]661eb9d2009-02-03 02:11:48306 webwidget_->Paint(canvas, rect);
initial.commit09911bf2008-07-26 23:55:29307
308 // Flush to underlying bitmap. TODO(darin): is this needed?
[email protected]661eb9d2009-02-03 02:11:48309 canvas->getTopPlatformDevice().accessBitmap(false);
initial.commit09911bf2008-07-26 23:55:29310
311 // Let the subclass observe this paint operations.
312 DidPaint();
313}
314
initial.commit09911bf2008-07-26 23:55:29315void RenderWidget::DoDeferredPaint() {
316 if (!webwidget_ || paint_reply_pending() || paint_rect_.IsEmpty())
317 return;
318
319 // When we are hidden, we want to suppress painting, but we still need to
320 // mark this DoDeferredPaint as complete.
321 if (is_hidden_ || size_.IsEmpty()) {
322 paint_rect_ = gfx::Rect();
323 needs_repainting_on_restore_ = true;
324 return;
325 }
326
327 // Layout may generate more invalidation...
328 webwidget_->Layout();
329
330 // OK, save the current paint_rect to a local since painting may cause more
331 // invalidation. Some WebCore rendering objects only layout when painted.
332 gfx::Rect damaged_rect = paint_rect_;
333 paint_rect_ = gfx::Rect();
334
335 // Compute a buffer for painting and cache it.
[email protected]e68e62fa2009-02-20 02:00:04336 skia::PlatformCanvas* canvas =
[email protected]f09c7182009-03-10 12:54:04337 RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_,
338 damaged_rect);
[email protected]e68e62fa2009-02-20 02:00:04339 if (!canvas) {
initial.commit09911bf2008-07-26 23:55:29340 NOTREACHED();
341 return;
342 }
343
[email protected]e68e62fa2009-02-20 02:00:04344 PaintRect(damaged_rect, canvas);
initial.commit09911bf2008-07-26 23:55:29345
346 ViewHostMsg_PaintRect_Params params;
initial.commit09911bf2008-07-26 23:55:29347 params.bitmap_rect = damaged_rect;
348 params.view_size = size_;
349 params.plugin_window_moves = plugin_window_moves_;
350 params.flags = next_paint_flags_;
[email protected]e68e62fa2009-02-20 02:00:04351 params.bitmap = current_paint_buf_->id();
initial.commit09911bf2008-07-26 23:55:29352
[email protected]e68e62fa2009-02-20 02:00:04353 delete canvas;
[email protected]661eb9d2009-02-03 02:11:48354
initial.commit09911bf2008-07-26 23:55:29355 plugin_window_moves_.clear();
356
357 paint_reply_pending_ = true;
358 Send(new ViewHostMsg_PaintRect(routing_id_, params));
359 next_paint_flags_ = 0;
360
361 UpdateIME();
362}
363
364void RenderWidget::DoDeferredScroll() {
365 if (!webwidget_ || scroll_reply_pending() || scroll_rect_.IsEmpty())
366 return;
367
368 // When we are hidden, we want to suppress scrolling, but we still need to
369 // mark this DoDeferredScroll as complete.
370 if (is_hidden_ || size_.IsEmpty()) {
371 scroll_rect_ = gfx::Rect();
372 needs_repainting_on_restore_ = true;
373 return;
374 }
375
376 // Layout may generate more invalidation, so we might have to bail on
377 // optimized scrolling...
378 webwidget_->Layout();
379
380 if (scroll_rect_.IsEmpty())
381 return;
382
383 gfx::Rect damaged_rect;
384
385 // Compute the region we will expose by scrolling, and paint that into a
386 // shared memory section.
387 if (scroll_delta_.x()) {
388 int dx = scroll_delta_.x();
389 damaged_rect.set_y(scroll_rect_.y());
390 damaged_rect.set_height(scroll_rect_.height());
391 if (dx > 0) {
392 damaged_rect.set_x(scroll_rect_.x());
393 damaged_rect.set_width(dx);
394 } else {
395 damaged_rect.set_x(scroll_rect_.right() + dx);
396 damaged_rect.set_width(-dx);
397 }
398 } else {
399 int dy = scroll_delta_.y();
400 damaged_rect.set_x(scroll_rect_.x());
401 damaged_rect.set_width(scroll_rect_.width());
402 if (dy > 0) {
403 damaged_rect.set_y(scroll_rect_.y());
404 damaged_rect.set_height(dy);
405 } else {
406 damaged_rect.set_y(scroll_rect_.bottom() + dy);
407 damaged_rect.set_height(-dy);
408 }
409 }
410
411 // In case the scroll offset exceeds the width/height of the scroll rect
412 damaged_rect = scroll_rect_.Intersect(damaged_rect);
413
[email protected]e68e62fa2009-02-20 02:00:04414 skia::PlatformCanvas* canvas =
[email protected]f09c7182009-03-10 12:54:04415 RenderProcess::current()->GetDrawingCanvas(&current_scroll_buf_,
416 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) {
[email protected]f911f742009-02-27 02:17:02485 if (dx != 0 && dy != 0) {
486 // We only support scrolling along one axis at a time.
487 DidScrollRect(webwidget, 0, dy, clip_rect);
488 dy = 0;
489 }
initial.commit09911bf2008-07-26 23:55:29490
491 bool intersects_with_painting = paint_rect_.Intersects(clip_rect);
492
493 // If we already have a pending scroll operation or if this scroll operation
494 // intersects the existing paint region, then just failover to invalidating.
495 if (!scroll_rect_.IsEmpty() || intersects_with_painting) {
496 if (!intersects_with_painting && scroll_rect_ == clip_rect) {
497 // OK, we can just update the scroll delta (requires same scrolling axis)
498 if (!dx && !scroll_delta_.x()) {
499 scroll_delta_.set_y(scroll_delta_.y() + dy);
500 return;
501 }
502 if (!dy && !scroll_delta_.y()) {
503 scroll_delta_.set_x(scroll_delta_.x() + dx);
504 return;
505 }
506 }
507 DidInvalidateRect(webwidget_, scroll_rect_);
508 DCHECK(scroll_rect_.IsEmpty());
509 DidInvalidateRect(webwidget_, clip_rect);
510 return;
511 }
512
513 // We only want one pending DoDeferredScroll call at any time...
514 bool scroll_pending = !scroll_rect_.IsEmpty();
515
516 scroll_rect_ = clip_rect;
517 scroll_delta_.SetPoint(dx, dy);
518
519 if (scroll_pending)
520 return;
521
522 // Perform scrolling asynchronously since we need to call WebView::Paint
523 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
524 this, &RenderWidget::DoDeferredScroll));
525}
526
527void RenderWidget::SetCursor(WebWidget* webwidget, const WebCursor& cursor) {
528 // Only send a SetCursor message if we need to make a change.
529 if (!current_cursor_.IsEqual(cursor)) {
530 current_cursor_ = cursor;
531 Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
532 }
533}
534
535// We are supposed to get a single call to Show for a newly created RenderWidget
536// that was created via RenderWidget::CreateWebView. So, we wait until this
537// point to dispatch the ShowWidget message.
538//
539// This method provides us with the information about how to display the newly
540// created RenderWidget (i.e., as a constrained popup or as a new tab).
541//
542void RenderWidget::Show(WebWidget* webwidget,
543 WindowOpenDisposition disposition) {
544 DCHECK(!did_show_) << "received extraneous Show call";
545 DCHECK(routing_id_ != MSG_ROUTING_NONE);
546 DCHECK(opener_id_ != MSG_ROUTING_NONE);
547
548 if (!did_show_) {
549 did_show_ = true;
550 // NOTE: initial_pos_ may still have its default values at this point, but
551 // that's okay. It'll be ignored if as_popup is false, or the browser
552 // process will impose a default position otherwise.
[email protected]8085dbc82008-09-26 22:53:44553 render_thread_->Send(new ViewHostMsg_ShowWidget(
initial.commit09911bf2008-07-26 23:55:29554 opener_id_, routing_id_, initial_pos_));
555 }
556}
557
558void RenderWidget::Focus(WebWidget* webwidget) {
559 // Prevent the widget from stealing the focus if it does not have focus
560 // already. We do this by explicitely setting the focus to false again.
561 // We only let the browser focus the renderer.
562 if (!has_focus_ && webwidget_) {
563 MessageLoop::current()->PostTask(FROM_HERE,
564 NewRunnableMethod(this, &RenderWidget::ClearFocus));
565 }
566}
567
568void RenderWidget::Blur(WebWidget* webwidget) {
569 Send(new ViewHostMsg_Blur(routing_id_));
570}
571
572void RenderWidget::CloseWidgetSoon(WebWidget* webwidget) {
573 // If a page calls window.close() twice, we'll end up here twice, but that's
574 // OK. It is safe to send multiple Close messages.
575
576 // Ask the RenderWidgetHost to initiate close.
577 Send(new ViewHostMsg_Close(routing_id_));
578}
579
580void RenderWidget::Close() {
581 if (webwidget_) {
582 webwidget_->Close();
583 webwidget_ = NULL;
584 }
585}
586
[email protected]63bf66f2008-08-21 21:13:01587void RenderWidget::GetWindowRect(WebWidget* webwidget, gfx::Rect* rect) {
588 Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, rect));
initial.commit09911bf2008-07-26 23:55:29589}
590
591void RenderWidget::SetWindowRect(WebWidget* webwidget, const gfx::Rect& pos) {
592 if (did_show_) {
593 Send(new ViewHostMsg_RequestMove(routing_id_, pos));
594 } else {
595 initial_pos_ = pos;
596 }
597}
598
[email protected]d4547452008-08-28 18:36:37599void RenderWidget::GetRootWindowRect(WebWidget* webwidget, gfx::Rect* rect) {
600 Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, rect));
601}
602
[email protected]08157312009-01-30 00:34:11603void RenderWidget::GetRootWindowResizerRect(WebWidget* webwidget,
[email protected]c04b6362008-11-21 18:54:19604 gfx::Rect* rect) {
[email protected]fb63b722009-02-19 18:05:14605 *rect = resizer_rect_;
[email protected]c04b6362008-11-21 18:54:19606}
607
initial.commit09911bf2008-07-26 23:55:29608void RenderWidget::OnImeSetInputMode(bool is_active) {
[email protected]c4bb35a2008-10-31 17:54:03609 // To prevent this renderer process from sending unnecessary IPC messages to
610 // a browser process, we permit the renderer process to send IPC messages
611 // only during the IME attached to the browser process is active.
initial.commit09911bf2008-07-26 23:55:29612 ime_is_active_ = is_active;
initial.commit09911bf2008-07-26 23:55:29613}
614
615void RenderWidget::OnImeSetComposition(int string_type,
616 int cursor_position,
617 int target_start, int target_end,
618 const std::wstring& ime_string) {
619 if (webwidget_) {
[email protected]9f23f592008-11-17 08:36:34620 ime_control_busy_ = true;
initial.commit09911bf2008-07-26 23:55:29621 webwidget_->ImeSetComposition(string_type, cursor_position,
622 target_start, target_end,
[email protected]34f6bc12008-11-06 07:40:53623 ime_string);
[email protected]9f23f592008-11-17 08:36:34624 ime_control_busy_ = false;
initial.commit09911bf2008-07-26 23:55:29625 }
626}
627
[email protected]ec7dc112008-08-06 05:30:12628void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) {
629 // During shutdown we can just ignore this message.
630 if (!webwidget_)
631 return;
632
633 set_next_paint_is_repaint_ack();
634 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height());
635 DidInvalidateRect(webwidget_, repaint_rect);
636}
637
[email protected]674741932009-02-04 23:44:46638bool RenderWidget::next_paint_is_resize_ack() const {
639 return ViewHostMsg_PaintRect_Flags::is_resize_ack(next_paint_flags_);
640}
641
642bool RenderWidget::next_paint_is_restore_ack() const {
643 return ViewHostMsg_PaintRect_Flags::is_restore_ack(next_paint_flags_);
644}
645
646void RenderWidget::set_next_paint_is_resize_ack() {
647 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESIZE_ACK;
648}
649
650void RenderWidget::set_next_paint_is_restore_ack() {
651 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESTORE_ACK;
652}
653
654void RenderWidget::set_next_paint_is_repaint_ack() {
655 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_REPAINT_ACK;
656}
657
initial.commit09911bf2008-07-26 23:55:29658void RenderWidget::UpdateIME() {
659 // If a browser process does not have IMEs, its IMEs are not active, or there
660 // are not any attached widgets.
661 // a renderer process does not have to retrieve information of the focused
662 // control or send notification messages to a browser process.
663 if (!ime_is_active_) {
664 return;
665 }
[email protected]34f6bc12008-11-06 07:40:53666 // Retrieve the caret position from the focused widget and verify we should
667 // enabled IMEs attached to the browser process.
668 bool enable_ime = false;
[email protected]34f6bc12008-11-06 07:40:53669 gfx::Rect caret_rect;
670 if (!webwidget_ ||
[email protected]8dcfd8c92009-02-20 16:15:12671 !webwidget_->ImeUpdateStatus(&enable_ime, &caret_rect)) {
initial.commit09911bf2008-07-26 23:55:29672 // There are not any editable widgets attached to this process.
673 // We should disable the IME to prevent it from sending CJK strings to
674 // non-editable widgets.
675 ime_control_updated_ = true;
676 ime_control_new_state_ = false;
677 }
[email protected]9f23f592008-11-17 08:36:34678 if (ime_control_new_state_ != enable_ime) {
679 ime_control_updated_ = true;
680 ime_control_new_state_ = enable_ime;
681 }
initial.commit09911bf2008-07-26 23:55:29682 if (ime_control_updated_) {
683 // The input focus has been changed.
684 // Compare the current state with the updated state and choose actions.
685 if (ime_control_enable_ime_) {
686 if (ime_control_new_state_) {
687 // Case 1: a text input -> another text input
688 // Complete the current composition and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53689 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
690 IME_COMPLETE_COMPOSITION,
691 caret_rect));
initial.commit09911bf2008-07-26 23:55:29692 } else {
693 // Case 2: a text input -> a password input (or a static control)
694 // Complete the current composition and disable the IME.
[email protected]34f6bc12008-11-06 07:40:53695 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_DISABLE,
696 caret_rect));
initial.commit09911bf2008-07-26 23:55:29697 }
698 } else {
699 if (ime_control_new_state_) {
700 // Case 3: a password input (or a static control) -> a text input
701 // Enable the IME and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53702 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
703 IME_COMPLETE_COMPOSITION,
704 caret_rect));
initial.commit09911bf2008-07-26 23:55:29705 } else {
706 // Case 4: a password input (or a static contol) -> another password
707 // input (or another static control).
708 // The IME has been already disabled and we don't have to do anything.
709 }
710 }
711 } else {
712 // The input focus is not changed.
713 // Notify the caret position to a browser process only if it is changed.
714 if (ime_control_enable_ime_) {
[email protected]34f6bc12008-11-06 07:40:53715 if (caret_rect.x() != ime_control_x_ ||
716 caret_rect.y() != ime_control_y_) {
717 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_MOVE_WINDOWS,
718 caret_rect));
initial.commit09911bf2008-07-26 23:55:29719 }
720 }
721 }
722 // Save the updated IME status to prevent from sending the same IPC messages.
723 ime_control_updated_ = false;
724 ime_control_enable_ime_ = ime_control_new_state_;
[email protected]34f6bc12008-11-06 07:40:53725 ime_control_x_ = caret_rect.x();
726 ime_control_y_ = caret_rect.y();
initial.commit09911bf2008-07-26 23:55:29727}
728
729void RenderWidget::DidMove(WebWidget* webwidget,
730 const WebPluginGeometry& move) {
731 size_t i = 0;
732 for (; i < plugin_window_moves_.size(); ++i) {
733 if (plugin_window_moves_[i].window == move.window) {
734 plugin_window_moves_[i] = move;
735 break;
736 }
737 }
738
739 if (i == plugin_window_moves_.size())
740 plugin_window_moves_.push_back(move);
741}