blob: 5b9e0c30357a765fd38982ee29063c3ef23e1e77 [file] [log] [blame]
[email protected]05d478752009-04-08 23:38:161// Copyright (c) 2009 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// 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"
[email protected]d5282e72009-05-13 13:16:5217#include "third_party/skia/include/core/SkShader.h"
[email protected]afdcf5c2009-05-10 20:30:4118#include "webkit/api/public/WebRect.h"
19#include "webkit/api/public/WebScreenInfo.h"
20#include "webkit/api/public/WebSize.h"
[email protected]661eb9d2009-02-03 02:11:4821
22#if defined(OS_POSIX)
[email protected]d5282e72009-05-13 13:16:5223#include "third_party/skia/include/core/SkPixelRef.h"
24#include "third_party/skia/include/core/SkMallocPixelRef.h"
[email protected]661eb9d2009-02-03 02:11:4825#endif // defined(OS_POSIX)
[email protected]8085dbc82008-09-26 22:53:4426
[email protected]07f953332009-03-25 04:31:1127#include "webkit/glue/webtextdirection.h"
initial.commit09911bf2008-07-26 23:55:2928#include "webkit/glue/webwidget.h"
29
[email protected]62cb33cae2009-03-27 23:30:2230using WebKit::WebInputEvent;
[email protected]b3f2b912009-04-09 16:18:5231using WebKit::WebRect;
[email protected]12456fa2009-04-01 23:07:1932using WebKit::WebScreenInfo;
[email protected]b3f2b912009-04-09 16:18:5233using WebKit::WebSize;
[email protected]62cb33cae2009-03-27 23:30:2234
[email protected]cfd727f2009-01-09 20:21:1135RenderWidget::RenderWidget(RenderThreadBase* render_thread, bool activatable)
initial.commit09911bf2008-07-26 23:55:2936 : routing_id_(MSG_ROUTING_NONE),
[email protected]c5b3b5e2009-02-13 06:41:1137 webwidget_(NULL),
initial.commit09911bf2008-07-26 23:55:2938 opener_id_(MSG_ROUTING_NONE),
[email protected]8085dbc82008-09-26 22:53:4439 render_thread_(render_thread),
initial.commit09911bf2008-07-26 23:55:2940 host_window_(NULL),
41 current_paint_buf_(NULL),
42 current_scroll_buf_(NULL),
43 next_paint_flags_(0),
44 paint_reply_pending_(false),
45 did_show_(false),
initial.commit09911bf2008-07-26 23:55:2946 is_hidden_(false),
47 needs_repainting_on_restore_(false),
48 has_focus_(false),
[email protected]661eb9d2009-02-03 02:11:4849 closing_(false),
initial.commit09911bf2008-07-26 23:55:2950 ime_is_active_(false),
51 ime_control_enable_ime_(true),
52 ime_control_x_(-1),
53 ime_control_y_(-1),
54 ime_control_new_state_(false),
[email protected]0ebf3872008-11-07 21:35:0355 ime_control_updated_(false),
[email protected]9f23f592008-11-17 08:36:3456 ime_control_busy_(false),
[email protected]2533ce12009-05-09 00:02:2457 activatable_(activatable),
58 pending_window_rect_count_(0) {
[email protected]8930d472009-02-21 08:05:2859 RenderProcess::current()->AddRefProcess();
[email protected]8085dbc82008-09-26 22:53:4460 DCHECK(render_thread_);
initial.commit09911bf2008-07-26 23:55:2961}
62
63RenderWidget::~RenderWidget() {
[email protected]c5b3b5e2009-02-13 06:41:1164 DCHECK(!webwidget_) << "Leaking our WebWidget!";
initial.commit09911bf2008-07-26 23:55:2965 if (current_paint_buf_) {
[email protected]8930d472009-02-21 08:05:2866 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
initial.commit09911bf2008-07-26 23:55:2967 current_paint_buf_ = NULL;
68 }
69 if (current_scroll_buf_) {
[email protected]8930d472009-02-21 08:05:2870 RenderProcess::current()->ReleaseTransportDIB(current_scroll_buf_);
initial.commit09911bf2008-07-26 23:55:2971 current_scroll_buf_ = NULL;
72 }
[email protected]8930d472009-02-21 08:05:2873 RenderProcess::current()->ReleaseProcess();
initial.commit09911bf2008-07-26 23:55:2974}
75
76/*static*/
[email protected]8085dbc82008-09-26 22:53:4477RenderWidget* RenderWidget::Create(int32 opener_id,
[email protected]0ebf3872008-11-07 21:35:0378 RenderThreadBase* render_thread,
[email protected]cfd727f2009-01-09 20:21:1179 bool activatable) {
initial.commit09911bf2008-07-26 23:55:2980 DCHECK(opener_id != MSG_ROUTING_NONE);
[email protected]0ebf3872008-11-07 21:35:0381 scoped_refptr<RenderWidget> widget = new RenderWidget(render_thread,
[email protected]cfd727f2009-01-09 20:21:1182 activatable);
initial.commit09911bf2008-07-26 23:55:2983 widget->Init(opener_id); // adds reference
84 return widget;
85}
86
87void RenderWidget::Init(int32 opener_id) {
88 DCHECK(!webwidget_);
89
90 if (opener_id != MSG_ROUTING_NONE)
91 opener_id_ = opener_id;
92
[email protected]c5b3b5e2009-02-13 06:41:1193 webwidget_ = WebWidget::Create(this);
initial.commit09911bf2008-07-26 23:55:2994
[email protected]8085dbc82008-09-26 22:53:4495 bool result = render_thread_->Send(
[email protected]cfd727f2009-01-09 20:21:1196 new ViewHostMsg_CreateWidget(opener_id, activatable_, &routing_id_));
initial.commit09911bf2008-07-26 23:55:2997 if (result) {
[email protected]8085dbc82008-09-26 22:53:4498 render_thread_->AddRoute(routing_id_, this);
initial.commit09911bf2008-07-26 23:55:2999 // Take a reference on behalf of the RenderThread. This will be balanced
100 // when we receive ViewMsg_Close.
101 AddRef();
102 } else {
103 DCHECK(false);
104 }
105}
106
107// This is used to complete pending inits and non-pending inits. For non-
108// pending cases, the parent will be the same as the current parent. This
109// indicates we do not need to reparent or anything.
[email protected]18bcc3c2009-01-27 21:39:15110void RenderWidget::CompleteInit(gfx::NativeViewId parent_hwnd) {
initial.commit09911bf2008-07-26 23:55:29111 DCHECK(routing_id_ != MSG_ROUTING_NONE);
initial.commit09911bf2008-07-26 23:55:29112
113 host_window_ = parent_hwnd;
114
[email protected]6de74452009-02-25 18:04:59115 Send(new ViewHostMsg_RenderViewReady(routing_id_));
initial.commit09911bf2008-07-26 23:55:29116}
117
118IPC_DEFINE_MESSAGE_MAP(RenderWidget)
119 IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
120 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
121 IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize)
122 IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden)
123 IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored)
124 IPC_MESSAGE_HANDLER(ViewMsg_PaintRect_ACK, OnPaintRectAck)
125 IPC_MESSAGE_HANDLER(ViewMsg_ScrollRect_ACK, OnScrollRectAck)
126 IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent)
127 IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost)
128 IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus)
129 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetInputMode, OnImeSetInputMode)
130 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition)
[email protected]ec7dc112008-08-06 05:30:12131 IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint)
[email protected]07f953332009-03-25 04:31:11132 IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection)
[email protected]2533ce12009-05-09 00:02:24133 IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck)
initial.commit09911bf2008-07-26 23:55:29134 IPC_MESSAGE_UNHANDLED_ERROR()
135IPC_END_MESSAGE_MAP()
136
137bool RenderWidget::Send(IPC::Message* message) {
138 // Don't send any messages after the browser has told us to close.
139 if (closing_) {
140 delete message;
141 return false;
142 }
143
144 // If given a messsage without a routing ID, then assign our routing ID.
145 if (message->routing_id() == MSG_ROUTING_NONE)
146 message->set_routing_id(routing_id_);
147
[email protected]d3fc25652009-02-24 22:31:25148 return render_thread_->Send(message);
[email protected]8085dbc82008-09-26 22:53:44149}
150
initial.commit09911bf2008-07-26 23:55:29151// Got a response from the browser after the renderer decided to create a new
152// view.
[email protected]18bcc3c2009-01-27 21:39:15153void RenderWidget::OnCreatingNewAck(gfx::NativeViewId parent) {
initial.commit09911bf2008-07-26 23:55:29154 DCHECK(routing_id_ != MSG_ROUTING_NONE);
155
156 CompleteInit(parent);
157}
158
159void RenderWidget::OnClose() {
160 if (closing_)
161 return;
162 closing_ = true;
163
164 // Browser correspondence is no longer needed at this point.
165 if (routing_id_ != MSG_ROUTING_NONE)
[email protected]8085dbc82008-09-26 22:53:44166 render_thread_->RemoveRoute(routing_id_);
initial.commit09911bf2008-07-26 23:55:29167
initial.commit09911bf2008-07-26 23:55:29168 // If there is a Send call on the stack, then it could be dangerous to close
[email protected]d3fc25652009-02-24 22:31:25169 // now. Post a task that only gets invoked when there are no nested message
170 // loops.
171 MessageLoop::current()->PostNonNestableTask(FROM_HERE,
172 NewRunnableMethod(this, &RenderWidget::Close));
173
174 // Balances the AddRef taken when we called AddRoute.
175 Release();
initial.commit09911bf2008-07-26 23:55:29176}
177
[email protected]f21c613a2009-02-12 14:46:17178void RenderWidget::OnResize(const gfx::Size& new_size,
179 const gfx::Rect& resizer_rect) {
initial.commit09911bf2008-07-26 23:55:29180 // During shutdown we can just ignore this message.
181 if (!webwidget_)
182 return;
183
[email protected]f21c613a2009-02-12 14:46:17184 // Remember the rect where the resize corner will be drawn.
185 resizer_rect_ = resizer_rect;
186
initial.commit09911bf2008-07-26 23:55:29187 // TODO(darin): We should not need to reset this here.
188 is_hidden_ = false;
189 needs_repainting_on_restore_ = false;
190
191 // We shouldn't be asked to resize to our current size.
192 DCHECK(size_ != new_size);
193 size_ = new_size;
194
195 // We should not be sent a Resize message if we have not ACK'd the previous
196 DCHECK(!next_paint_is_resize_ack());
197
198 // When resizing, we want to wait to paint before ACK'ing the resize. This
199 // ensures that we only resize as fast as we can paint. We only need to send
200 // an ACK if we are resized to a non-empty rect.
201 webwidget_->Resize(new_size);
202 if (!new_size.IsEmpty()) {
[email protected]2d5d09d52009-06-15 14:29:21203 DCHECK(!paint_rect_.IsEmpty());
initial.commit09911bf2008-07-26 23:55:29204
205 // This should have caused an invalidation of the entire view. The damaged
206 // rect could be larger than new_size if we are being made smaller.
[email protected]2d5d09d52009-06-15 14:29:21207 DCHECK_GE(paint_rect_.width(), new_size.width());
208 DCHECK_GE(paint_rect_.height(), new_size.height());
209
initial.commit09911bf2008-07-26 23:55:29210 // We will send the Resize_ACK flag once we paint again.
211 set_next_paint_is_resize_ack();
212 }
213}
214
215void RenderWidget::OnWasHidden() {
216 // Go into a mode where we stop generating paint and scrolling events.
217 is_hidden_ = true;
218}
219
220void RenderWidget::OnWasRestored(bool needs_repainting) {
221 // During shutdown we can just ignore this message.
222 if (!webwidget_)
223 return;
224
225 // See OnWasHidden
226 is_hidden_ = false;
227
228 if (!needs_repainting && !needs_repainting_on_restore_)
229 return;
230 needs_repainting_on_restore_ = false;
231
232 // Tag the next paint as a restore ack, which is picked up by DoDeferredPaint
233 // when it sends out the next PaintRect message.
234 set_next_paint_is_restore_ack();
235
236 // Generate a full repaint.
237 DidInvalidateRect(webwidget_, gfx::Rect(size_.width(), size_.height()));
238}
239
[email protected]b7fce1f2008-08-14 05:01:07240void RenderWidget::OnPaintRectAck() {
initial.commit09911bf2008-07-26 23:55:29241 DCHECK(paint_reply_pending());
242 paint_reply_pending_ = false;
[email protected]b7fce1f2008-08-14 05:01:07243 // If we sent a PaintRect message with a zero-sized bitmap, then
244 // we should have no current paint buf.
245 if (current_paint_buf_) {
[email protected]8930d472009-02-21 08:05:28246 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_);
[email protected]b7fce1f2008-08-14 05:01:07247 current_paint_buf_ = NULL;
initial.commit09911bf2008-07-26 23:55:29248 }
[email protected]e68e62fa2009-02-20 02:00:04249
initial.commit09911bf2008-07-26 23:55:29250 // Continue painting if necessary...
251 DoDeferredPaint();
252}
253
[email protected]2533ce12009-05-09 00:02:24254void RenderWidget::OnRequestMoveAck() {
255 DCHECK(pending_window_rect_count_);
256 pending_window_rect_count_--;
257}
258
initial.commit09911bf2008-07-26 23:55:29259void RenderWidget::OnScrollRectAck() {
260 DCHECK(scroll_reply_pending());
261
[email protected]e68e62fa2009-02-20 02:00:04262 if (current_scroll_buf_) {
[email protected]8930d472009-02-21 08:05:28263 RenderProcess::current()->ReleaseTransportDIB(current_scroll_buf_);
[email protected]e68e62fa2009-02-20 02:00:04264 current_scroll_buf_ = NULL;
265 }
initial.commit09911bf2008-07-26 23:55:29266
267 // Continue scrolling if necessary...
268 DoDeferredScroll();
269}
270
271void RenderWidget::OnHandleInputEvent(const IPC::Message& message) {
272 void* iter = NULL;
273
274 const char* data;
275 int data_length;
276 if (!message.ReadData(&iter, &data, &data_length))
277 return;
278
279 const WebInputEvent* input_event =
280 reinterpret_cast<const WebInputEvent*>(data);
281 bool processed = false;
282 if (webwidget_)
283 processed = webwidget_->HandleInputEvent(input_event);
284
285 IPC::Message* response = new ViewHostMsg_HandleInputEvent_ACK(routing_id_);
286 response->WriteInt(input_event->type);
[email protected]e2824412009-02-27 01:57:05287 response->WriteBool(processed);
288
initial.commit09911bf2008-07-26 23:55:29289 Send(response);
290}
291
292void RenderWidget::OnMouseCaptureLost() {
293 if (webwidget_)
294 webwidget_->MouseCaptureLost();
295}
296
297void RenderWidget::OnSetFocus(bool enable) {
298 has_focus_ = enable;
299 if (webwidget_)
300 webwidget_->SetFocus(enable);
301 if (enable) {
302 // Force to retrieve the state of the focused widget to determine if we
303 // should activate IMEs next time when this process calls the UpdateIME()
304 // function.
305 ime_control_updated_ = true;
306 ime_control_new_state_ = true;
307 }
308}
309
310void RenderWidget::ClearFocus() {
311 // We may have got the focus from the browser before this gets processed, in
312 // which case we do not want to unfocus ourself.
313 if (!has_focus_ && webwidget_)
314 webwidget_->SetFocus(false);
315}
316
[email protected]2d5d09d52009-06-15 14:29:21317void RenderWidget::PaintRect(const gfx::Rect& rect,
318 skia::PlatformCanvas* canvas) {
319
320 // Bring the canvas into the coordinate system of the paint rect.
321 canvas->translate(static_cast<SkScalar>(-rect.x()),
322 static_cast<SkScalar>(-rect.y()));
[email protected]96c3499a2009-05-02 18:31:03323
[email protected]699ab0d2009-04-23 23:19:14324 // If there is a custom background, tile it.
325 if (!background_.empty()) {
[email protected]699ab0d2009-04-23 23:19:14326 SkPaint paint;
327 SkShader* shader = SkShader::CreateBitmapShader(background_,
328 SkShader::kRepeat_TileMode,
329 SkShader::kRepeat_TileMode);
330 paint.setShader(shader)->unref();
[email protected]8860e4f52009-06-25 01:01:52331 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
[email protected]699ab0d2009-04-23 23:19:14332 canvas->drawPaint(paint);
[email protected]699ab0d2009-04-23 23:19:14333 }
334
[email protected]661eb9d2009-02-03 02:11:48335 webwidget_->Paint(canvas, rect);
initial.commit09911bf2008-07-26 23:55:29336
337 // Flush to underlying bitmap. TODO(darin): is this needed?
[email protected]661eb9d2009-02-03 02:11:48338 canvas->getTopPlatformDevice().accessBitmap(false);
initial.commit09911bf2008-07-26 23:55:29339}
340
initial.commit09911bf2008-07-26 23:55:29341void RenderWidget::DoDeferredPaint() {
[email protected]2d5d09d52009-06-15 14:29:21342 if (!webwidget_ || paint_reply_pending() || paint_rect_.IsEmpty())
initial.commit09911bf2008-07-26 23:55:29343 return;
344
345 // When we are hidden, we want to suppress painting, but we still need to
346 // mark this DoDeferredPaint as complete.
347 if (is_hidden_ || size_.IsEmpty()) {
[email protected]2d5d09d52009-06-15 14:29:21348 paint_rect_ = gfx::Rect();
initial.commit09911bf2008-07-26 23:55:29349 needs_repainting_on_restore_ = true;
350 return;
351 }
352
353 // Layout may generate more invalidation...
354 webwidget_->Layout();
355
356 // OK, save the current paint_rect to a local since painting may cause more
357 // invalidation. Some WebCore rendering objects only layout when painted.
[email protected]2d5d09d52009-06-15 14:29:21358 gfx::Rect damaged_rect = paint_rect_;
359 paint_rect_ = gfx::Rect();
initial.commit09911bf2008-07-26 23:55:29360
361 // Compute a buffer for painting and cache it.
[email protected]e68e62fa2009-02-20 02:00:04362 skia::PlatformCanvas* canvas =
[email protected]f09c7182009-03-10 12:54:04363 RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_,
[email protected]2d5d09d52009-06-15 14:29:21364 damaged_rect);
[email protected]e68e62fa2009-02-20 02:00:04365 if (!canvas) {
initial.commit09911bf2008-07-26 23:55:29366 NOTREACHED();
367 return;
368 }
369
[email protected]955ee6d62009-06-17 21:53:03370 // We may get back a smaller canvas than we asked for.
371 damaged_rect.set_width(canvas->getDevice()->width());
372 damaged_rect.set_height(canvas->getDevice()->height());
373
[email protected]2d5d09d52009-06-15 14:29:21374 PaintRect(damaged_rect, canvas);
initial.commit09911bf2008-07-26 23:55:29375
376 ViewHostMsg_PaintRect_Params params;
[email protected]2d5d09d52009-06-15 14:29:21377 params.bitmap_rect = damaged_rect;
initial.commit09911bf2008-07-26 23:55:29378 params.view_size = size_;
379 params.plugin_window_moves = plugin_window_moves_;
380 params.flags = next_paint_flags_;
[email protected]2d5d09d52009-06-15 14:29:21381 params.bitmap = current_paint_buf_->id();
initial.commit09911bf2008-07-26 23:55:29382
[email protected]e68e62fa2009-02-20 02:00:04383 delete canvas;
[email protected]661eb9d2009-02-03 02:11:48384
initial.commit09911bf2008-07-26 23:55:29385 plugin_window_moves_.clear();
386
387 paint_reply_pending_ = true;
388 Send(new ViewHostMsg_PaintRect(routing_id_, params));
389 next_paint_flags_ = 0;
390
391 UpdateIME();
392}
393
394void RenderWidget::DoDeferredScroll() {
395 if (!webwidget_ || scroll_reply_pending() || scroll_rect_.IsEmpty())
396 return;
397
398 // When we are hidden, we want to suppress scrolling, but we still need to
399 // mark this DoDeferredScroll as complete.
400 if (is_hidden_ || size_.IsEmpty()) {
401 scroll_rect_ = gfx::Rect();
402 needs_repainting_on_restore_ = true;
403 return;
404 }
405
406 // Layout may generate more invalidation, so we might have to bail on
407 // optimized scrolling...
408 webwidget_->Layout();
409
410 if (scroll_rect_.IsEmpty())
411 return;
412
413 gfx::Rect damaged_rect;
414
415 // Compute the region we will expose by scrolling, and paint that into a
416 // shared memory section.
417 if (scroll_delta_.x()) {
418 int dx = scroll_delta_.x();
419 damaged_rect.set_y(scroll_rect_.y());
420 damaged_rect.set_height(scroll_rect_.height());
421 if (dx > 0) {
422 damaged_rect.set_x(scroll_rect_.x());
423 damaged_rect.set_width(dx);
424 } else {
425 damaged_rect.set_x(scroll_rect_.right() + dx);
426 damaged_rect.set_width(-dx);
427 }
428 } else {
429 int dy = scroll_delta_.y();
430 damaged_rect.set_x(scroll_rect_.x());
431 damaged_rect.set_width(scroll_rect_.width());
432 if (dy > 0) {
433 damaged_rect.set_y(scroll_rect_.y());
434 damaged_rect.set_height(dy);
435 } else {
436 damaged_rect.set_y(scroll_rect_.bottom() + dy);
437 damaged_rect.set_height(-dy);
438 }
439 }
440
441 // In case the scroll offset exceeds the width/height of the scroll rect
442 damaged_rect = scroll_rect_.Intersect(damaged_rect);
443
[email protected]e68e62fa2009-02-20 02:00:04444 skia::PlatformCanvas* canvas =
[email protected]f09c7182009-03-10 12:54:04445 RenderProcess::current()->GetDrawingCanvas(&current_scroll_buf_,
446 damaged_rect);
[email protected]e68e62fa2009-02-20 02:00:04447 if (!canvas) {
initial.commit09911bf2008-07-26 23:55:29448 NOTREACHED();
449 return;
450 }
451
[email protected]955ee6d62009-06-17 21:53:03452 // We may get back a smaller canvas than we asked for.
453 damaged_rect.set_width(canvas->getDevice()->width());
454 damaged_rect.set_height(canvas->getDevice()->height());
455
initial.commit09911bf2008-07-26 23:55:29456 // Set these parameters before calling Paint, since that could result in
457 // further invalidates (uncommon).
458 ViewHostMsg_ScrollRect_Params params;
initial.commit09911bf2008-07-26 23:55:29459 params.bitmap_rect = damaged_rect;
460 params.dx = scroll_delta_.x();
461 params.dy = scroll_delta_.y();
462 params.clip_rect = scroll_rect_;
463 params.view_size = size_;
464 params.plugin_window_moves = plugin_window_moves_;
[email protected]e68e62fa2009-02-20 02:00:04465 params.bitmap = current_scroll_buf_->id();
[email protected]661eb9d2009-02-03 02:11:48466
initial.commit09911bf2008-07-26 23:55:29467 plugin_window_moves_.clear();
468
469 // Mark the scroll operation as no longer pending.
470 scroll_rect_ = gfx::Rect();
471
[email protected]e68e62fa2009-02-20 02:00:04472 PaintRect(damaged_rect, canvas);
initial.commit09911bf2008-07-26 23:55:29473 Send(new ViewHostMsg_ScrollRect(routing_id_, params));
[email protected]e68e62fa2009-02-20 02:00:04474 delete canvas;
initial.commit09911bf2008-07-26 23:55:29475 UpdateIME();
476}
477
478///////////////////////////////////////////////////////////////////////////////
479// WebWidgetDelegate
480
[email protected]18bcc3c2009-01-27 21:39:15481gfx::NativeViewId RenderWidget::GetContainingView(WebWidget* webwidget) {
initial.commit09911bf2008-07-26 23:55:29482 return host_window_;
483}
484
485void RenderWidget::DidInvalidateRect(WebWidget* webwidget,
[email protected]b3f2b912009-04-09 16:18:52486 const WebRect& rect) {
initial.commit09911bf2008-07-26 23:55:29487 // We only want one pending DoDeferredPaint call at any time...
[email protected]2d5d09d52009-06-15 14:29:21488 bool paint_pending = !paint_rect_.IsEmpty();
initial.commit09911bf2008-07-26 23:55:29489
490 // If this invalidate overlaps with a pending scroll, then we have to
491 // downgrade to invalidating the scroll rect.
[email protected]b3f2b912009-04-09 16:18:52492 if (gfx::Rect(rect).Intersects(scroll_rect_)) {
[email protected]2d5d09d52009-06-15 14:29:21493 paint_rect_ = paint_rect_.Union(scroll_rect_);
initial.commit09911bf2008-07-26 23:55:29494 scroll_rect_ = gfx::Rect();
495 }
496
[email protected]2d5d09d52009-06-15 14:29:21497 gfx::Rect view_rect(0, 0, size_.width(), size_.height());
498 // TODO(iyengar) Investigate why we have painting issues when
499 // we ignore invalid regions outside the view.
500 // Ignore invalidates that occur outside the bounds of the view
501 // TODO(darin): maybe this should move into the paint code?
502 // paint_rect_ = view_rect.Intersect(paint_rect_.Union(rect));
503 paint_rect_ = paint_rect_.Union(view_rect.Intersect(rect));
initial.commit09911bf2008-07-26 23:55:29504
[email protected]2d5d09d52009-06-15 14:29:21505 if (paint_rect_.IsEmpty() || paint_reply_pending() || paint_pending)
initial.commit09911bf2008-07-26 23:55:29506 return;
507
508 // Perform painting asynchronously. This serves two purposes:
509 // 1) Ensures that we call WebView::Paint without a bunch of other junk
510 // on the call stack.
511 // 2) Allows us to collect more damage rects before painting to help coalesce
512 // the work that we will need to do.
513 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
514 this, &RenderWidget::DoDeferredPaint));
515}
516
517void RenderWidget::DidScrollRect(WebWidget* webwidget, int dx, int dy,
[email protected]b3f2b912009-04-09 16:18:52518 const WebRect& clip_rect) {
[email protected]f911f742009-02-27 02:17:02519 if (dx != 0 && dy != 0) {
520 // We only support scrolling along one axis at a time.
521 DidScrollRect(webwidget, 0, dy, clip_rect);
522 dy = 0;
523 }
initial.commit09911bf2008-07-26 23:55:29524
[email protected]2d5d09d52009-06-15 14:29:21525 bool intersects_with_painting = paint_rect_.Intersects(clip_rect);
initial.commit09911bf2008-07-26 23:55:29526
527 // If we already have a pending scroll operation or if this scroll operation
528 // intersects the existing paint region, then just failover to invalidating.
529 if (!scroll_rect_.IsEmpty() || intersects_with_painting) {
[email protected]b3f2b912009-04-09 16:18:52530 if (!intersects_with_painting && scroll_rect_ == gfx::Rect(clip_rect)) {
initial.commit09911bf2008-07-26 23:55:29531 // OK, we can just update the scroll delta (requires same scrolling axis)
532 if (!dx && !scroll_delta_.x()) {
533 scroll_delta_.set_y(scroll_delta_.y() + dy);
534 return;
535 }
536 if (!dy && !scroll_delta_.y()) {
537 scroll_delta_.set_x(scroll_delta_.x() + dx);
538 return;
539 }
540 }
541 DidInvalidateRect(webwidget_, scroll_rect_);
542 DCHECK(scroll_rect_.IsEmpty());
543 DidInvalidateRect(webwidget_, clip_rect);
544 return;
545 }
546
547 // We only want one pending DoDeferredScroll call at any time...
548 bool scroll_pending = !scroll_rect_.IsEmpty();
549
550 scroll_rect_ = clip_rect;
551 scroll_delta_.SetPoint(dx, dy);
552
553 if (scroll_pending)
554 return;
555
556 // Perform scrolling asynchronously since we need to call WebView::Paint
557 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
558 this, &RenderWidget::DoDeferredScroll));
559}
560
561void RenderWidget::SetCursor(WebWidget* webwidget, const WebCursor& cursor) {
562 // Only send a SetCursor message if we need to make a change.
563 if (!current_cursor_.IsEqual(cursor)) {
564 current_cursor_ = cursor;
565 Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
566 }
567}
568
569// We are supposed to get a single call to Show for a newly created RenderWidget
570// that was created via RenderWidget::CreateWebView. So, we wait until this
571// point to dispatch the ShowWidget message.
572//
573// This method provides us with the information about how to display the newly
574// created RenderWidget (i.e., as a constrained popup or as a new tab).
575//
576void RenderWidget::Show(WebWidget* webwidget,
577 WindowOpenDisposition disposition) {
578 DCHECK(!did_show_) << "received extraneous Show call";
579 DCHECK(routing_id_ != MSG_ROUTING_NONE);
580 DCHECK(opener_id_ != MSG_ROUTING_NONE);
581
582 if (!did_show_) {
583 did_show_ = true;
584 // NOTE: initial_pos_ may still have its default values at this point, but
585 // that's okay. It'll be ignored if as_popup is false, or the browser
586 // process will impose a default position otherwise.
[email protected]8085dbc82008-09-26 22:53:44587 render_thread_->Send(new ViewHostMsg_ShowWidget(
initial.commit09911bf2008-07-26 23:55:29588 opener_id_, routing_id_, initial_pos_));
[email protected]2533ce12009-05-09 00:02:24589 SetPendingWindowRect(initial_pos_);
initial.commit09911bf2008-07-26 23:55:29590 }
591}
592
[email protected]3f64e5af2009-04-10 03:03:09593void RenderWidget::ShowAsPopupWithItems(WebWidget* webwidget,
594 const WebRect& bounds,
595 int item_height,
596 int selected_index,
597 const std::vector<WebMenuItem>& items) {
[email protected]e344a052009-04-24 21:12:11598 ViewHostMsg_ShowPopup_Params params;
599 params.bounds = bounds;
600 params.item_height = item_height;
601 params.selected_item = selected_index;
602 params.popup_items = items;
603
604 Send(new ViewHostMsg_ShowPopup(routing_id_, params));
[email protected]6b013182009-03-24 19:05:03605}
606
initial.commit09911bf2008-07-26 23:55:29607void RenderWidget::Focus(WebWidget* webwidget) {
608 // Prevent the widget from stealing the focus if it does not have focus
609 // already. We do this by explicitely setting the focus to false again.
610 // We only let the browser focus the renderer.
611 if (!has_focus_ && webwidget_) {
612 MessageLoop::current()->PostTask(FROM_HERE,
613 NewRunnableMethod(this, &RenderWidget::ClearFocus));
614 }
615}
616
617void RenderWidget::Blur(WebWidget* webwidget) {
618 Send(new ViewHostMsg_Blur(routing_id_));
619}
620
[email protected]2533ce12009-05-09 00:02:24621void RenderWidget::DoDeferredClose() {
622 Send(new ViewHostMsg_Close(routing_id_));
623}
624
initial.commit09911bf2008-07-26 23:55:29625void RenderWidget::CloseWidgetSoon(WebWidget* webwidget) {
626 // If a page calls window.close() twice, we'll end up here twice, but that's
627 // OK. It is safe to send multiple Close messages.
628
[email protected]2533ce12009-05-09 00:02:24629 // Ask the RenderWidgetHost to initiate close. We could be called from deep
630 // in Javascript. If we ask the RendwerWidgetHost to close now, the window
631 // could be closed before the JS finishes executing. So instead, post a
632 // message back to the message loop, which won't run until the JS is
633 // complete, and then the Close message can be sent.
634 MessageLoop::current()->PostNonNestableTask(FROM_HERE, NewRunnableMethod(
635 this, &RenderWidget::DoDeferredClose));
initial.commit09911bf2008-07-26 23:55:29636}
637
[email protected]b4b967e2009-04-22 11:33:05638void RenderWidget::GenerateFullRepaint() {
639 DidInvalidateRect(webwidget_, gfx::Rect(size_.width(), size_.height()));
640}
641
initial.commit09911bf2008-07-26 23:55:29642void RenderWidget::Close() {
643 if (webwidget_) {
644 webwidget_->Close();
645 webwidget_ = NULL;
646 }
647}
648
[email protected]b3f2b912009-04-09 16:18:52649void RenderWidget::GetWindowRect(WebWidget* webwidget, WebRect* result) {
[email protected]2533ce12009-05-09 00:02:24650 if (pending_window_rect_count_) {
651 *result = pending_window_rect_;
652 return;
653 }
654
[email protected]b3f2b912009-04-09 16:18:52655 gfx::Rect rect;
656 Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, &rect));
657 *result = rect;
initial.commit09911bf2008-07-26 23:55:29658}
659
[email protected]cd9832fe2009-05-04 18:11:20660void RenderWidget::SetWindowRect(WebWidget* webwidget, const WebRect& pos) {
initial.commit09911bf2008-07-26 23:55:29661 if (did_show_) {
662 Send(new ViewHostMsg_RequestMove(routing_id_, pos));
[email protected]2533ce12009-05-09 00:02:24663 SetPendingWindowRect(pos);
initial.commit09911bf2008-07-26 23:55:29664 } else {
665 initial_pos_ = pos;
666 }
667}
668
[email protected]2533ce12009-05-09 00:02:24669void RenderWidget::SetPendingWindowRect(const WebRect& rect) {
670 pending_window_rect_ = rect;
671 pending_window_rect_count_++;
672}
673
[email protected]b3f2b912009-04-09 16:18:52674void RenderWidget::GetRootWindowRect(WebWidget* webwidget, WebRect* result) {
[email protected]2533ce12009-05-09 00:02:24675 if (pending_window_rect_count_) {
676 // NOTE(mbelshe): If there is a pending_window_rect_, then getting
677 // the RootWindowRect is probably going to return wrong results since the
678 // browser may not have processed the Move yet. There isn't really anything
679 // good to do in this case, and it shouldn't happen - since this size is
680 // only really needed for windowToScreen, which is only used for Popups.
681 *result = pending_window_rect_;
682 return;
683 }
684
[email protected]b3f2b912009-04-09 16:18:52685 gfx::Rect rect;
686 Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, &rect));
687 *result = rect;
[email protected]d4547452008-08-28 18:36:37688}
689
[email protected]08157312009-01-30 00:34:11690void RenderWidget::GetRootWindowResizerRect(WebWidget* webwidget,
[email protected]b3f2b912009-04-09 16:18:52691 WebRect* rect) {
[email protected]fb63b722009-02-19 18:05:14692 *rect = resizer_rect_;
[email protected]c04b6362008-11-21 18:54:19693}
694
initial.commit09911bf2008-07-26 23:55:29695void RenderWidget::OnImeSetInputMode(bool is_active) {
[email protected]c4bb35a2008-10-31 17:54:03696 // To prevent this renderer process from sending unnecessary IPC messages to
697 // a browser process, we permit the renderer process to send IPC messages
698 // only during the IME attached to the browser process is active.
initial.commit09911bf2008-07-26 23:55:29699 ime_is_active_ = is_active;
initial.commit09911bf2008-07-26 23:55:29700}
701
702void RenderWidget::OnImeSetComposition(int string_type,
703 int cursor_position,
704 int target_start, int target_end,
705 const std::wstring& ime_string) {
706 if (webwidget_) {
[email protected]9f23f592008-11-17 08:36:34707 ime_control_busy_ = true;
initial.commit09911bf2008-07-26 23:55:29708 webwidget_->ImeSetComposition(string_type, cursor_position,
709 target_start, target_end,
[email protected]34f6bc12008-11-06 07:40:53710 ime_string);
[email protected]9f23f592008-11-17 08:36:34711 ime_control_busy_ = false;
initial.commit09911bf2008-07-26 23:55:29712 }
713}
714
[email protected]ec7dc112008-08-06 05:30:12715void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) {
716 // During shutdown we can just ignore this message.
717 if (!webwidget_)
718 return;
719
720 set_next_paint_is_repaint_ack();
721 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height());
722 DidInvalidateRect(webwidget_, repaint_rect);
723}
724
[email protected]07f953332009-03-25 04:31:11725void RenderWidget::OnSetTextDirection(int direction) {
726 if (!webwidget_)
727 return;
728
729 WebTextDirection new_direction = static_cast<WebTextDirection>(direction);
730 if (new_direction == WEB_TEXT_DIRECTION_DEFAULT ||
731 new_direction == WEB_TEXT_DIRECTION_LTR ||
732 new_direction == WEB_TEXT_DIRECTION_RTL) {
733 webwidget_->SetTextDirection(new_direction);
734 } else {
735 NOTREACHED();
736 }
737}
738
[email protected]699ab0d2009-04-23 23:19:14739void RenderWidget::SetBackground(const SkBitmap& background) {
740 background_ = background;
741 // Generate a full repaint.
742 DidInvalidateRect(webwidget_, gfx::Rect(size_.width(), size_.height()));
743}
744
[email protected]674741932009-02-04 23:44:46745bool RenderWidget::next_paint_is_resize_ack() const {
746 return ViewHostMsg_PaintRect_Flags::is_resize_ack(next_paint_flags_);
747}
748
749bool RenderWidget::next_paint_is_restore_ack() const {
750 return ViewHostMsg_PaintRect_Flags::is_restore_ack(next_paint_flags_);
751}
752
753void RenderWidget::set_next_paint_is_resize_ack() {
754 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESIZE_ACK;
755}
756
757void RenderWidget::set_next_paint_is_restore_ack() {
758 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESTORE_ACK;
759}
760
761void RenderWidget::set_next_paint_is_repaint_ack() {
762 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_REPAINT_ACK;
763}
764
initial.commit09911bf2008-07-26 23:55:29765void RenderWidget::UpdateIME() {
766 // If a browser process does not have IMEs, its IMEs are not active, or there
767 // are not any attached widgets.
768 // a renderer process does not have to retrieve information of the focused
769 // control or send notification messages to a browser process.
770 if (!ime_is_active_) {
771 return;
772 }
[email protected]34f6bc12008-11-06 07:40:53773 // Retrieve the caret position from the focused widget and verify we should
774 // enabled IMEs attached to the browser process.
775 bool enable_ime = false;
[email protected]b3f2b912009-04-09 16:18:52776 WebRect caret_rect;
[email protected]34f6bc12008-11-06 07:40:53777 if (!webwidget_ ||
[email protected]8dcfd8c92009-02-20 16:15:12778 !webwidget_->ImeUpdateStatus(&enable_ime, &caret_rect)) {
initial.commit09911bf2008-07-26 23:55:29779 // There are not any editable widgets attached to this process.
780 // We should disable the IME to prevent it from sending CJK strings to
781 // non-editable widgets.
782 ime_control_updated_ = true;
783 ime_control_new_state_ = false;
784 }
[email protected]9f23f592008-11-17 08:36:34785 if (ime_control_new_state_ != enable_ime) {
786 ime_control_updated_ = true;
787 ime_control_new_state_ = enable_ime;
788 }
initial.commit09911bf2008-07-26 23:55:29789 if (ime_control_updated_) {
790 // The input focus has been changed.
791 // Compare the current state with the updated state and choose actions.
792 if (ime_control_enable_ime_) {
793 if (ime_control_new_state_) {
794 // Case 1: a text input -> another text input
795 // Complete the current composition and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53796 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
797 IME_COMPLETE_COMPOSITION,
798 caret_rect));
initial.commit09911bf2008-07-26 23:55:29799 } else {
800 // Case 2: a text input -> a password input (or a static control)
801 // Complete the current composition and disable the IME.
[email protected]34f6bc12008-11-06 07:40:53802 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_DISABLE,
803 caret_rect));
initial.commit09911bf2008-07-26 23:55:29804 }
805 } else {
806 if (ime_control_new_state_) {
807 // Case 3: a password input (or a static control) -> a text input
808 // Enable the IME and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53809 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
810 IME_COMPLETE_COMPOSITION,
811 caret_rect));
initial.commit09911bf2008-07-26 23:55:29812 } else {
813 // Case 4: a password input (or a static contol) -> another password
814 // input (or another static control).
815 // The IME has been already disabled and we don't have to do anything.
816 }
817 }
818 } else {
819 // The input focus is not changed.
820 // Notify the caret position to a browser process only if it is changed.
821 if (ime_control_enable_ime_) {
[email protected]b3f2b912009-04-09 16:18:52822 if (caret_rect.x != ime_control_x_ ||
823 caret_rect.y != ime_control_y_) {
[email protected]34f6bc12008-11-06 07:40:53824 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_MOVE_WINDOWS,
825 caret_rect));
initial.commit09911bf2008-07-26 23:55:29826 }
827 }
828 }
829 // Save the updated IME status to prevent from sending the same IPC messages.
830 ime_control_updated_ = false;
831 ime_control_enable_ime_ = ime_control_new_state_;
[email protected]b3f2b912009-04-09 16:18:52832 ime_control_x_ = caret_rect.x;
833 ime_control_y_ = caret_rect.y;
initial.commit09911bf2008-07-26 23:55:29834}
835
836void RenderWidget::DidMove(WebWidget* webwidget,
837 const WebPluginGeometry& move) {
838 size_t i = 0;
839 for (; i < plugin_window_moves_.size(); ++i) {
840 if (plugin_window_moves_[i].window == move.window) {
841 plugin_window_moves_[i] = move;
842 break;
843 }
844 }
845
846 if (i == plugin_window_moves_.size())
847 plugin_window_moves_.push_back(move);
848}
[email protected]12456fa2009-04-01 23:07:19849
850WebScreenInfo RenderWidget::GetScreenInfo(WebWidget* webwidget) {
851 WebScreenInfo results;
852 RenderThread::current()->Send(
853 new ViewHostMsg_GetScreenInfo(host_window_, &results));
854 return results;
855}