blob: 5929a7d4b42acda30af7aaad139b9a4da615c1d4 [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]8930d472009-02-21 08:05:28337 RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_, damaged_rect);
[email protected]e68e62fa2009-02-20 02:00:04338 if (!canvas) {
initial.commit09911bf2008-07-26 23:55:29339 NOTREACHED();
340 return;
341 }
342
[email protected]e68e62fa2009-02-20 02:00:04343 PaintRect(damaged_rect, canvas);
initial.commit09911bf2008-07-26 23:55:29344
345 ViewHostMsg_PaintRect_Params params;
initial.commit09911bf2008-07-26 23:55:29346 params.bitmap_rect = damaged_rect;
347 params.view_size = size_;
348 params.plugin_window_moves = plugin_window_moves_;
349 params.flags = next_paint_flags_;
[email protected]e68e62fa2009-02-20 02:00:04350 params.bitmap = current_paint_buf_->id();
initial.commit09911bf2008-07-26 23:55:29351
[email protected]e68e62fa2009-02-20 02:00:04352 delete canvas;
[email protected]661eb9d2009-02-03 02:11:48353
initial.commit09911bf2008-07-26 23:55:29354 plugin_window_moves_.clear();
355
356 paint_reply_pending_ = true;
357 Send(new ViewHostMsg_PaintRect(routing_id_, params));
358 next_paint_flags_ = 0;
359
360 UpdateIME();
361}
362
363void RenderWidget::DoDeferredScroll() {
364 if (!webwidget_ || scroll_reply_pending() || scroll_rect_.IsEmpty())
365 return;
366
367 // When we are hidden, we want to suppress scrolling, but we still need to
368 // mark this DoDeferredScroll as complete.
369 if (is_hidden_ || size_.IsEmpty()) {
370 scroll_rect_ = gfx::Rect();
371 needs_repainting_on_restore_ = true;
372 return;
373 }
374
375 // Layout may generate more invalidation, so we might have to bail on
376 // optimized scrolling...
377 webwidget_->Layout();
378
379 if (scroll_rect_.IsEmpty())
380 return;
381
382 gfx::Rect damaged_rect;
383
384 // Compute the region we will expose by scrolling, and paint that into a
385 // shared memory section.
386 if (scroll_delta_.x()) {
387 int dx = scroll_delta_.x();
388 damaged_rect.set_y(scroll_rect_.y());
389 damaged_rect.set_height(scroll_rect_.height());
390 if (dx > 0) {
391 damaged_rect.set_x(scroll_rect_.x());
392 damaged_rect.set_width(dx);
393 } else {
394 damaged_rect.set_x(scroll_rect_.right() + dx);
395 damaged_rect.set_width(-dx);
396 }
397 } else {
398 int dy = scroll_delta_.y();
399 damaged_rect.set_x(scroll_rect_.x());
400 damaged_rect.set_width(scroll_rect_.width());
401 if (dy > 0) {
402 damaged_rect.set_y(scroll_rect_.y());
403 damaged_rect.set_height(dy);
404 } else {
405 damaged_rect.set_y(scroll_rect_.bottom() + dy);
406 damaged_rect.set_height(-dy);
407 }
408 }
409
410 // In case the scroll offset exceeds the width/height of the scroll rect
411 damaged_rect = scroll_rect_.Intersect(damaged_rect);
412
[email protected]e68e62fa2009-02-20 02:00:04413 skia::PlatformCanvas* canvas =
[email protected]8930d472009-02-21 08:05:28414 RenderProcess::current()->GetDrawingCanvas(&current_scroll_buf_, damaged_rect);
[email protected]e68e62fa2009-02-20 02:00:04415 if (!canvas) {
initial.commit09911bf2008-07-26 23:55:29416 NOTREACHED();
417 return;
418 }
419
420 // Set these parameters before calling Paint, since that could result in
421 // further invalidates (uncommon).
422 ViewHostMsg_ScrollRect_Params params;
initial.commit09911bf2008-07-26 23:55:29423 params.bitmap_rect = damaged_rect;
424 params.dx = scroll_delta_.x();
425 params.dy = scroll_delta_.y();
426 params.clip_rect = scroll_rect_;
427 params.view_size = size_;
428 params.plugin_window_moves = plugin_window_moves_;
[email protected]e68e62fa2009-02-20 02:00:04429 params.bitmap = current_scroll_buf_->id();
[email protected]661eb9d2009-02-03 02:11:48430
initial.commit09911bf2008-07-26 23:55:29431 plugin_window_moves_.clear();
432
433 // Mark the scroll operation as no longer pending.
434 scroll_rect_ = gfx::Rect();
435
[email protected]e68e62fa2009-02-20 02:00:04436 PaintRect(damaged_rect, canvas);
initial.commit09911bf2008-07-26 23:55:29437 Send(new ViewHostMsg_ScrollRect(routing_id_, params));
[email protected]e68e62fa2009-02-20 02:00:04438 delete canvas;
initial.commit09911bf2008-07-26 23:55:29439 UpdateIME();
440}
441
442///////////////////////////////////////////////////////////////////////////////
443// WebWidgetDelegate
444
[email protected]18bcc3c2009-01-27 21:39:15445gfx::NativeViewId RenderWidget::GetContainingView(WebWidget* webwidget) {
initial.commit09911bf2008-07-26 23:55:29446 return host_window_;
447}
448
449void RenderWidget::DidInvalidateRect(WebWidget* webwidget,
450 const gfx::Rect& rect) {
451 // We only want one pending DoDeferredPaint call at any time...
452 bool paint_pending = !paint_rect_.IsEmpty();
453
454 // If this invalidate overlaps with a pending scroll, then we have to
455 // downgrade to invalidating the scroll rect.
456 if (rect.Intersects(scroll_rect_)) {
457 paint_rect_ = paint_rect_.Union(scroll_rect_);
458 scroll_rect_ = gfx::Rect();
459 }
460
461 gfx::Rect view_rect(0, 0, size_.width(), size_.height());
462 // TODO(iyengar) Investigate why we have painting issues when
463 // we ignore invalid regions outside the view.
464 // Ignore invalidates that occur outside the bounds of the view
465 // TODO(darin): maybe this should move into the paint code?
466 // paint_rect_ = view_rect.Intersect(paint_rect_.Union(rect));
467 paint_rect_ = paint_rect_.Union(view_rect.Intersect(rect));
468
469 if (paint_rect_.IsEmpty() || paint_reply_pending() || paint_pending)
470 return;
471
472 // Perform painting asynchronously. This serves two purposes:
473 // 1) Ensures that we call WebView::Paint without a bunch of other junk
474 // on the call stack.
475 // 2) Allows us to collect more damage rects before painting to help coalesce
476 // the work that we will need to do.
477 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
478 this, &RenderWidget::DoDeferredPaint));
479}
480
481void RenderWidget::DidScrollRect(WebWidget* webwidget, int dx, int dy,
482 const gfx::Rect& clip_rect) {
483 // We only support scrolling along one axis at a time.
484 DCHECK((dx && !dy) || (!dx && dy));
485
486 bool intersects_with_painting = paint_rect_.Intersects(clip_rect);
487
488 // If we already have a pending scroll operation or if this scroll operation
489 // intersects the existing paint region, then just failover to invalidating.
490 if (!scroll_rect_.IsEmpty() || intersects_with_painting) {
491 if (!intersects_with_painting && scroll_rect_ == clip_rect) {
492 // OK, we can just update the scroll delta (requires same scrolling axis)
493 if (!dx && !scroll_delta_.x()) {
494 scroll_delta_.set_y(scroll_delta_.y() + dy);
495 return;
496 }
497 if (!dy && !scroll_delta_.y()) {
498 scroll_delta_.set_x(scroll_delta_.x() + dx);
499 return;
500 }
501 }
502 DidInvalidateRect(webwidget_, scroll_rect_);
503 DCHECK(scroll_rect_.IsEmpty());
504 DidInvalidateRect(webwidget_, clip_rect);
505 return;
506 }
507
508 // We only want one pending DoDeferredScroll call at any time...
509 bool scroll_pending = !scroll_rect_.IsEmpty();
510
511 scroll_rect_ = clip_rect;
512 scroll_delta_.SetPoint(dx, dy);
513
514 if (scroll_pending)
515 return;
516
517 // Perform scrolling asynchronously since we need to call WebView::Paint
518 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
519 this, &RenderWidget::DoDeferredScroll));
520}
521
522void RenderWidget::SetCursor(WebWidget* webwidget, const WebCursor& cursor) {
523 // Only send a SetCursor message if we need to make a change.
524 if (!current_cursor_.IsEqual(cursor)) {
525 current_cursor_ = cursor;
526 Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
527 }
528}
529
530// We are supposed to get a single call to Show for a newly created RenderWidget
531// that was created via RenderWidget::CreateWebView. So, we wait until this
532// point to dispatch the ShowWidget message.
533//
534// This method provides us with the information about how to display the newly
535// created RenderWidget (i.e., as a constrained popup or as a new tab).
536//
537void RenderWidget::Show(WebWidget* webwidget,
538 WindowOpenDisposition disposition) {
539 DCHECK(!did_show_) << "received extraneous Show call";
540 DCHECK(routing_id_ != MSG_ROUTING_NONE);
541 DCHECK(opener_id_ != MSG_ROUTING_NONE);
542
543 if (!did_show_) {
544 did_show_ = true;
545 // NOTE: initial_pos_ may still have its default values at this point, but
546 // that's okay. It'll be ignored if as_popup is false, or the browser
547 // process will impose a default position otherwise.
[email protected]8085dbc82008-09-26 22:53:44548 render_thread_->Send(new ViewHostMsg_ShowWidget(
initial.commit09911bf2008-07-26 23:55:29549 opener_id_, routing_id_, initial_pos_));
550 }
551}
552
553void RenderWidget::Focus(WebWidget* webwidget) {
554 // Prevent the widget from stealing the focus if it does not have focus
555 // already. We do this by explicitely setting the focus to false again.
556 // We only let the browser focus the renderer.
557 if (!has_focus_ && webwidget_) {
558 MessageLoop::current()->PostTask(FROM_HERE,
559 NewRunnableMethod(this, &RenderWidget::ClearFocus));
560 }
561}
562
563void RenderWidget::Blur(WebWidget* webwidget) {
564 Send(new ViewHostMsg_Blur(routing_id_));
565}
566
567void RenderWidget::CloseWidgetSoon(WebWidget* webwidget) {
568 // If a page calls window.close() twice, we'll end up here twice, but that's
569 // OK. It is safe to send multiple Close messages.
570
571 // Ask the RenderWidgetHost to initiate close.
572 Send(new ViewHostMsg_Close(routing_id_));
573}
574
575void RenderWidget::Close() {
576 if (webwidget_) {
577 webwidget_->Close();
578 webwidget_ = NULL;
579 }
580}
581
[email protected]63bf66f2008-08-21 21:13:01582void RenderWidget::GetWindowRect(WebWidget* webwidget, gfx::Rect* rect) {
583 Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, rect));
initial.commit09911bf2008-07-26 23:55:29584}
585
586void RenderWidget::SetWindowRect(WebWidget* webwidget, const gfx::Rect& pos) {
587 if (did_show_) {
588 Send(new ViewHostMsg_RequestMove(routing_id_, pos));
589 } else {
590 initial_pos_ = pos;
591 }
592}
593
[email protected]d4547452008-08-28 18:36:37594void RenderWidget::GetRootWindowRect(WebWidget* webwidget, gfx::Rect* rect) {
595 Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, rect));
596}
597
[email protected]08157312009-01-30 00:34:11598void RenderWidget::GetRootWindowResizerRect(WebWidget* webwidget,
[email protected]c04b6362008-11-21 18:54:19599 gfx::Rect* rect) {
[email protected]f21c613a2009-02-12 14:46:17600 // This is disabled to verify if WebKit is responsible for the slow down
601 // that was witnessed in the page cycler tests when the resize corner
602 // code was commited...
[email protected]fb63b722009-02-19 18:05:14603#if defined(OS_MACOSX)
604 // ...we need it enabled on Mac so scrollbars are usable.
605 *rect = resizer_rect_;
606#elif defined(OS_WIN) || defined(OS_LINUX)
[email protected]f21c613a2009-02-12 14:46:17607 *rect = gfx::Rect(); // resizer_rect_;
[email protected]fb63b722009-02-19 18:05:14608#endif
[email protected]c04b6362008-11-21 18:54:19609}
610
initial.commit09911bf2008-07-26 23:55:29611void RenderWidget::OnImeSetInputMode(bool is_active) {
[email protected]c4bb35a2008-10-31 17:54:03612 // To prevent this renderer process from sending unnecessary IPC messages to
613 // a browser process, we permit the renderer process to send IPC messages
614 // only during the IME attached to the browser process is active.
initial.commit09911bf2008-07-26 23:55:29615 ime_is_active_ = is_active;
initial.commit09911bf2008-07-26 23:55:29616}
617
618void RenderWidget::OnImeSetComposition(int string_type,
619 int cursor_position,
620 int target_start, int target_end,
621 const std::wstring& ime_string) {
622 if (webwidget_) {
[email protected]9f23f592008-11-17 08:36:34623 ime_control_busy_ = true;
initial.commit09911bf2008-07-26 23:55:29624 webwidget_->ImeSetComposition(string_type, cursor_position,
625 target_start, target_end,
[email protected]34f6bc12008-11-06 07:40:53626 ime_string);
[email protected]9f23f592008-11-17 08:36:34627 ime_control_busy_ = false;
initial.commit09911bf2008-07-26 23:55:29628 }
629}
630
[email protected]ec7dc112008-08-06 05:30:12631void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) {
632 // During shutdown we can just ignore this message.
633 if (!webwidget_)
634 return;
635
636 set_next_paint_is_repaint_ack();
637 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height());
638 DidInvalidateRect(webwidget_, repaint_rect);
639}
640
[email protected]674741932009-02-04 23:44:46641bool RenderWidget::next_paint_is_resize_ack() const {
642 return ViewHostMsg_PaintRect_Flags::is_resize_ack(next_paint_flags_);
643}
644
645bool RenderWidget::next_paint_is_restore_ack() const {
646 return ViewHostMsg_PaintRect_Flags::is_restore_ack(next_paint_flags_);
647}
648
649void RenderWidget::set_next_paint_is_resize_ack() {
650 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESIZE_ACK;
651}
652
653void RenderWidget::set_next_paint_is_restore_ack() {
654 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESTORE_ACK;
655}
656
657void RenderWidget::set_next_paint_is_repaint_ack() {
658 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_REPAINT_ACK;
659}
660
initial.commit09911bf2008-07-26 23:55:29661void RenderWidget::UpdateIME() {
662 // If a browser process does not have IMEs, its IMEs are not active, or there
663 // are not any attached widgets.
664 // a renderer process does not have to retrieve information of the focused
665 // control or send notification messages to a browser process.
666 if (!ime_is_active_) {
667 return;
668 }
[email protected]34f6bc12008-11-06 07:40:53669 // Retrieve the caret position from the focused widget and verify we should
670 // enabled IMEs attached to the browser process.
671 bool enable_ime = false;
[email protected]34f6bc12008-11-06 07:40:53672 gfx::Rect caret_rect;
673 if (!webwidget_ ||
[email protected]8dcfd8c92009-02-20 16:15:12674 !webwidget_->ImeUpdateStatus(&enable_ime, &caret_rect)) {
initial.commit09911bf2008-07-26 23:55:29675 // There are not any editable widgets attached to this process.
676 // We should disable the IME to prevent it from sending CJK strings to
677 // non-editable widgets.
678 ime_control_updated_ = true;
679 ime_control_new_state_ = false;
680 }
[email protected]9f23f592008-11-17 08:36:34681 if (ime_control_new_state_ != enable_ime) {
682 ime_control_updated_ = true;
683 ime_control_new_state_ = enable_ime;
684 }
initial.commit09911bf2008-07-26 23:55:29685 if (ime_control_updated_) {
686 // The input focus has been changed.
687 // Compare the current state with the updated state and choose actions.
688 if (ime_control_enable_ime_) {
689 if (ime_control_new_state_) {
690 // Case 1: a text input -> another text input
691 // Complete the current composition and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53692 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
693 IME_COMPLETE_COMPOSITION,
694 caret_rect));
initial.commit09911bf2008-07-26 23:55:29695 } else {
696 // Case 2: a text input -> a password input (or a static control)
697 // Complete the current composition and disable the IME.
[email protected]34f6bc12008-11-06 07:40:53698 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_DISABLE,
699 caret_rect));
initial.commit09911bf2008-07-26 23:55:29700 }
701 } else {
702 if (ime_control_new_state_) {
703 // Case 3: a password input (or a static control) -> a text input
704 // Enable the IME and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53705 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
706 IME_COMPLETE_COMPOSITION,
707 caret_rect));
initial.commit09911bf2008-07-26 23:55:29708 } else {
709 // Case 4: a password input (or a static contol) -> another password
710 // input (or another static control).
711 // The IME has been already disabled and we don't have to do anything.
712 }
713 }
714 } else {
715 // The input focus is not changed.
716 // Notify the caret position to a browser process only if it is changed.
717 if (ime_control_enable_ime_) {
[email protected]34f6bc12008-11-06 07:40:53718 if (caret_rect.x() != ime_control_x_ ||
719 caret_rect.y() != ime_control_y_) {
720 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_MOVE_WINDOWS,
721 caret_rect));
initial.commit09911bf2008-07-26 23:55:29722 }
723 }
724 }
725 // Save the updated IME status to prevent from sending the same IPC messages.
726 ime_control_updated_ = false;
727 ime_control_enable_ime_ = ime_control_new_state_;
[email protected]34f6bc12008-11-06 07:40:53728 ime_control_x_ = caret_rect.x();
729 ime_control_y_ = caret_rect.y();
initial.commit09911bf2008-07-26 23:55:29730}
731
732void RenderWidget::DidMove(WebWidget* webwidget,
733 const WebPluginGeometry& move) {
734 size_t i = 0;
735 for (; i < plugin_window_moves_.size(); ++i) {
736 if (plugin_window_moves_[i].window == move.window) {
737 plugin_window_moves_[i] = move;
738 break;
739 }
740 }
741
742 if (i == plugin_window_moves_.size())
743 plugin_window_moves_.push_back(move);
744}