blob: 25afdbbb91c262c19c80341795b786c0e6c742e5 [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()) {
203 DCHECK(!paint_rect_.IsEmpty());
204
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.
207 DCHECK_GE(paint_rect_.width(), new_size.width());
208 DCHECK_GE(paint_rect_.height(), new_size.height());
209
210 // 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]176aa482008-11-14 03:25:15317void RenderWidget::PaintRect(const gfx::Rect& rect,
[email protected]661eb9d2009-02-03 02:11:48318 skia::PlatformCanvas* canvas) {
[email protected]699ab0d2009-04-23 23:19:14319
[email protected]96c3499a2009-05-02 18:31:03320 // 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()));
323
[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();
331 paint.setPorterDuffXfermode(SkPorterDuff::kSrcOver_Mode);
332 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 // Let the subclass observe this paint operations.
341 DidPaint();
342}
343
initial.commit09911bf2008-07-26 23:55:29344void RenderWidget::DoDeferredPaint() {
345 if (!webwidget_ || paint_reply_pending() || paint_rect_.IsEmpty())
346 return;
347
348 // When we are hidden, we want to suppress painting, but we still need to
349 // mark this DoDeferredPaint as complete.
350 if (is_hidden_ || size_.IsEmpty()) {
351 paint_rect_ = gfx::Rect();
352 needs_repainting_on_restore_ = true;
353 return;
354 }
355
356 // Layout may generate more invalidation...
357 webwidget_->Layout();
358
359 // OK, save the current paint_rect to a local since painting may cause more
360 // invalidation. Some WebCore rendering objects only layout when painted.
361 gfx::Rect damaged_rect = paint_rect_;
362 paint_rect_ = gfx::Rect();
363
364 // Compute a buffer for painting and cache it.
[email protected]e68e62fa2009-02-20 02:00:04365 skia::PlatformCanvas* canvas =
[email protected]f09c7182009-03-10 12:54:04366 RenderProcess::current()->GetDrawingCanvas(&current_paint_buf_,
367 damaged_rect);
[email protected]e68e62fa2009-02-20 02:00:04368 if (!canvas) {
initial.commit09911bf2008-07-26 23:55:29369 NOTREACHED();
370 return;
371 }
372
[email protected]e68e62fa2009-02-20 02:00:04373 PaintRect(damaged_rect, canvas);
initial.commit09911bf2008-07-26 23:55:29374
375 ViewHostMsg_PaintRect_Params params;
initial.commit09911bf2008-07-26 23:55:29376 params.bitmap_rect = damaged_rect;
377 params.view_size = size_;
378 params.plugin_window_moves = plugin_window_moves_;
379 params.flags = next_paint_flags_;
[email protected]e68e62fa2009-02-20 02:00:04380 params.bitmap = current_paint_buf_->id();
initial.commit09911bf2008-07-26 23:55:29381
[email protected]e68e62fa2009-02-20 02:00:04382 delete canvas;
[email protected]661eb9d2009-02-03 02:11:48383
initial.commit09911bf2008-07-26 23:55:29384 plugin_window_moves_.clear();
385
386 paint_reply_pending_ = true;
387 Send(new ViewHostMsg_PaintRect(routing_id_, params));
388 next_paint_flags_ = 0;
389
390 UpdateIME();
391}
392
393void RenderWidget::DoDeferredScroll() {
394 if (!webwidget_ || scroll_reply_pending() || scroll_rect_.IsEmpty())
395 return;
396
397 // When we are hidden, we want to suppress scrolling, but we still need to
398 // mark this DoDeferredScroll as complete.
399 if (is_hidden_ || size_.IsEmpty()) {
400 scroll_rect_ = gfx::Rect();
401 needs_repainting_on_restore_ = true;
402 return;
403 }
404
405 // Layout may generate more invalidation, so we might have to bail on
406 // optimized scrolling...
407 webwidget_->Layout();
408
409 if (scroll_rect_.IsEmpty())
410 return;
411
412 gfx::Rect damaged_rect;
413
414 // Compute the region we will expose by scrolling, and paint that into a
415 // shared memory section.
416 if (scroll_delta_.x()) {
417 int dx = scroll_delta_.x();
418 damaged_rect.set_y(scroll_rect_.y());
419 damaged_rect.set_height(scroll_rect_.height());
420 if (dx > 0) {
421 damaged_rect.set_x(scroll_rect_.x());
422 damaged_rect.set_width(dx);
423 } else {
424 damaged_rect.set_x(scroll_rect_.right() + dx);
425 damaged_rect.set_width(-dx);
426 }
427 } else {
428 int dy = scroll_delta_.y();
429 damaged_rect.set_x(scroll_rect_.x());
430 damaged_rect.set_width(scroll_rect_.width());
431 if (dy > 0) {
432 damaged_rect.set_y(scroll_rect_.y());
433 damaged_rect.set_height(dy);
434 } else {
435 damaged_rect.set_y(scroll_rect_.bottom() + dy);
436 damaged_rect.set_height(-dy);
437 }
438 }
439
440 // In case the scroll offset exceeds the width/height of the scroll rect
441 damaged_rect = scroll_rect_.Intersect(damaged_rect);
442
[email protected]e68e62fa2009-02-20 02:00:04443 skia::PlatformCanvas* canvas =
[email protected]f09c7182009-03-10 12:54:04444 RenderProcess::current()->GetDrawingCanvas(&current_scroll_buf_,
445 damaged_rect);
[email protected]e68e62fa2009-02-20 02:00:04446 if (!canvas) {
initial.commit09911bf2008-07-26 23:55:29447 NOTREACHED();
448 return;
449 }
450
451 // Set these parameters before calling Paint, since that could result in
452 // further invalidates (uncommon).
453 ViewHostMsg_ScrollRect_Params params;
initial.commit09911bf2008-07-26 23:55:29454 params.bitmap_rect = damaged_rect;
455 params.dx = scroll_delta_.x();
456 params.dy = scroll_delta_.y();
457 params.clip_rect = scroll_rect_;
458 params.view_size = size_;
459 params.plugin_window_moves = plugin_window_moves_;
[email protected]e68e62fa2009-02-20 02:00:04460 params.bitmap = current_scroll_buf_->id();
[email protected]661eb9d2009-02-03 02:11:48461
initial.commit09911bf2008-07-26 23:55:29462 plugin_window_moves_.clear();
463
464 // Mark the scroll operation as no longer pending.
465 scroll_rect_ = gfx::Rect();
466
[email protected]e68e62fa2009-02-20 02:00:04467 PaintRect(damaged_rect, canvas);
initial.commit09911bf2008-07-26 23:55:29468 Send(new ViewHostMsg_ScrollRect(routing_id_, params));
[email protected]e68e62fa2009-02-20 02:00:04469 delete canvas;
initial.commit09911bf2008-07-26 23:55:29470 UpdateIME();
471}
472
473///////////////////////////////////////////////////////////////////////////////
474// WebWidgetDelegate
475
[email protected]18bcc3c2009-01-27 21:39:15476gfx::NativeViewId RenderWidget::GetContainingView(WebWidget* webwidget) {
initial.commit09911bf2008-07-26 23:55:29477 return host_window_;
478}
479
480void RenderWidget::DidInvalidateRect(WebWidget* webwidget,
[email protected]b3f2b912009-04-09 16:18:52481 const WebRect& rect) {
initial.commit09911bf2008-07-26 23:55:29482 // We only want one pending DoDeferredPaint call at any time...
483 bool paint_pending = !paint_rect_.IsEmpty();
484
485 // If this invalidate overlaps with a pending scroll, then we have to
486 // downgrade to invalidating the scroll rect.
[email protected]b3f2b912009-04-09 16:18:52487 if (gfx::Rect(rect).Intersects(scroll_rect_)) {
initial.commit09911bf2008-07-26 23:55:29488 paint_rect_ = paint_rect_.Union(scroll_rect_);
489 scroll_rect_ = gfx::Rect();
490 }
491
492 gfx::Rect view_rect(0, 0, size_.width(), size_.height());
493 // TODO(iyengar) Investigate why we have painting issues when
494 // we ignore invalid regions outside the view.
495 // Ignore invalidates that occur outside the bounds of the view
496 // TODO(darin): maybe this should move into the paint code?
497 // paint_rect_ = view_rect.Intersect(paint_rect_.Union(rect));
498 paint_rect_ = paint_rect_.Union(view_rect.Intersect(rect));
499
500 if (paint_rect_.IsEmpty() || paint_reply_pending() || paint_pending)
501 return;
502
503 // Perform painting asynchronously. This serves two purposes:
504 // 1) Ensures that we call WebView::Paint without a bunch of other junk
505 // on the call stack.
506 // 2) Allows us to collect more damage rects before painting to help coalesce
507 // the work that we will need to do.
508 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
509 this, &RenderWidget::DoDeferredPaint));
510}
511
512void RenderWidget::DidScrollRect(WebWidget* webwidget, int dx, int dy,
[email protected]b3f2b912009-04-09 16:18:52513 const WebRect& clip_rect) {
[email protected]f911f742009-02-27 02:17:02514 if (dx != 0 && dy != 0) {
515 // We only support scrolling along one axis at a time.
516 DidScrollRect(webwidget, 0, dy, clip_rect);
517 dy = 0;
518 }
initial.commit09911bf2008-07-26 23:55:29519
520 bool intersects_with_painting = paint_rect_.Intersects(clip_rect);
521
522 // If we already have a pending scroll operation or if this scroll operation
523 // intersects the existing paint region, then just failover to invalidating.
524 if (!scroll_rect_.IsEmpty() || intersects_with_painting) {
[email protected]b3f2b912009-04-09 16:18:52525 if (!intersects_with_painting && scroll_rect_ == gfx::Rect(clip_rect)) {
initial.commit09911bf2008-07-26 23:55:29526 // OK, we can just update the scroll delta (requires same scrolling axis)
527 if (!dx && !scroll_delta_.x()) {
528 scroll_delta_.set_y(scroll_delta_.y() + dy);
529 return;
530 }
531 if (!dy && !scroll_delta_.y()) {
532 scroll_delta_.set_x(scroll_delta_.x() + dx);
533 return;
534 }
535 }
536 DidInvalidateRect(webwidget_, scroll_rect_);
537 DCHECK(scroll_rect_.IsEmpty());
538 DidInvalidateRect(webwidget_, clip_rect);
539 return;
540 }
541
542 // We only want one pending DoDeferredScroll call at any time...
543 bool scroll_pending = !scroll_rect_.IsEmpty();
544
545 scroll_rect_ = clip_rect;
546 scroll_delta_.SetPoint(dx, dy);
547
548 if (scroll_pending)
549 return;
550
551 // Perform scrolling asynchronously since we need to call WebView::Paint
552 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
553 this, &RenderWidget::DoDeferredScroll));
554}
555
556void RenderWidget::SetCursor(WebWidget* webwidget, const WebCursor& cursor) {
557 // Only send a SetCursor message if we need to make a change.
558 if (!current_cursor_.IsEqual(cursor)) {
559 current_cursor_ = cursor;
560 Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
561 }
562}
563
564// We are supposed to get a single call to Show for a newly created RenderWidget
565// that was created via RenderWidget::CreateWebView. So, we wait until this
566// point to dispatch the ShowWidget message.
567//
568// This method provides us with the information about how to display the newly
569// created RenderWidget (i.e., as a constrained popup or as a new tab).
570//
571void RenderWidget::Show(WebWidget* webwidget,
572 WindowOpenDisposition disposition) {
573 DCHECK(!did_show_) << "received extraneous Show call";
574 DCHECK(routing_id_ != MSG_ROUTING_NONE);
575 DCHECK(opener_id_ != MSG_ROUTING_NONE);
576
577 if (!did_show_) {
578 did_show_ = true;
579 // NOTE: initial_pos_ may still have its default values at this point, but
580 // that's okay. It'll be ignored if as_popup is false, or the browser
581 // process will impose a default position otherwise.
[email protected]8085dbc82008-09-26 22:53:44582 render_thread_->Send(new ViewHostMsg_ShowWidget(
initial.commit09911bf2008-07-26 23:55:29583 opener_id_, routing_id_, initial_pos_));
[email protected]2533ce12009-05-09 00:02:24584 SetPendingWindowRect(initial_pos_);
initial.commit09911bf2008-07-26 23:55:29585 }
586}
587
[email protected]3f64e5af2009-04-10 03:03:09588void RenderWidget::ShowAsPopupWithItems(WebWidget* webwidget,
589 const WebRect& bounds,
590 int item_height,
591 int selected_index,
592 const std::vector<WebMenuItem>& items) {
[email protected]e344a052009-04-24 21:12:11593 ViewHostMsg_ShowPopup_Params params;
594 params.bounds = bounds;
595 params.item_height = item_height;
596 params.selected_item = selected_index;
597 params.popup_items = items;
598
599 Send(new ViewHostMsg_ShowPopup(routing_id_, params));
[email protected]6b013182009-03-24 19:05:03600}
601
initial.commit09911bf2008-07-26 23:55:29602void RenderWidget::Focus(WebWidget* webwidget) {
603 // Prevent the widget from stealing the focus if it does not have focus
604 // already. We do this by explicitely setting the focus to false again.
605 // We only let the browser focus the renderer.
606 if (!has_focus_ && webwidget_) {
607 MessageLoop::current()->PostTask(FROM_HERE,
608 NewRunnableMethod(this, &RenderWidget::ClearFocus));
609 }
610}
611
612void RenderWidget::Blur(WebWidget* webwidget) {
613 Send(new ViewHostMsg_Blur(routing_id_));
614}
615
[email protected]2533ce12009-05-09 00:02:24616void RenderWidget::DoDeferredClose() {
617 Send(new ViewHostMsg_Close(routing_id_));
618}
619
initial.commit09911bf2008-07-26 23:55:29620void RenderWidget::CloseWidgetSoon(WebWidget* webwidget) {
621 // If a page calls window.close() twice, we'll end up here twice, but that's
622 // OK. It is safe to send multiple Close messages.
623
[email protected]2533ce12009-05-09 00:02:24624 // Ask the RenderWidgetHost to initiate close. We could be called from deep
625 // in Javascript. If we ask the RendwerWidgetHost to close now, the window
626 // could be closed before the JS finishes executing. So instead, post a
627 // message back to the message loop, which won't run until the JS is
628 // complete, and then the Close message can be sent.
629 MessageLoop::current()->PostNonNestableTask(FROM_HERE, NewRunnableMethod(
630 this, &RenderWidget::DoDeferredClose));
initial.commit09911bf2008-07-26 23:55:29631}
632
[email protected]b4b967e2009-04-22 11:33:05633void RenderWidget::GenerateFullRepaint() {
634 DidInvalidateRect(webwidget_, gfx::Rect(size_.width(), size_.height()));
635}
636
initial.commit09911bf2008-07-26 23:55:29637void RenderWidget::Close() {
638 if (webwidget_) {
639 webwidget_->Close();
640 webwidget_ = NULL;
641 }
642}
643
[email protected]b3f2b912009-04-09 16:18:52644void RenderWidget::GetWindowRect(WebWidget* webwidget, WebRect* result) {
[email protected]2533ce12009-05-09 00:02:24645 if (pending_window_rect_count_) {
646 *result = pending_window_rect_;
647 return;
648 }
649
[email protected]b3f2b912009-04-09 16:18:52650 gfx::Rect rect;
651 Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, &rect));
652 *result = rect;
initial.commit09911bf2008-07-26 23:55:29653}
654
[email protected]cd9832fe2009-05-04 18:11:20655void RenderWidget::SetWindowRect(WebWidget* webwidget, const WebRect& pos) {
initial.commit09911bf2008-07-26 23:55:29656 if (did_show_) {
657 Send(new ViewHostMsg_RequestMove(routing_id_, pos));
[email protected]2533ce12009-05-09 00:02:24658 SetPendingWindowRect(pos);
initial.commit09911bf2008-07-26 23:55:29659 } else {
660 initial_pos_ = pos;
661 }
662}
663
[email protected]2533ce12009-05-09 00:02:24664void RenderWidget::SetPendingWindowRect(const WebRect& rect) {
665 pending_window_rect_ = rect;
666 pending_window_rect_count_++;
667}
668
[email protected]b3f2b912009-04-09 16:18:52669void RenderWidget::GetRootWindowRect(WebWidget* webwidget, WebRect* result) {
[email protected]2533ce12009-05-09 00:02:24670 if (pending_window_rect_count_) {
671 // NOTE(mbelshe): If there is a pending_window_rect_, then getting
672 // the RootWindowRect is probably going to return wrong results since the
673 // browser may not have processed the Move yet. There isn't really anything
674 // good to do in this case, and it shouldn't happen - since this size is
675 // only really needed for windowToScreen, which is only used for Popups.
676 *result = pending_window_rect_;
677 return;
678 }
679
[email protected]b3f2b912009-04-09 16:18:52680 gfx::Rect rect;
681 Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, &rect));
682 *result = rect;
[email protected]d4547452008-08-28 18:36:37683}
684
[email protected]08157312009-01-30 00:34:11685void RenderWidget::GetRootWindowResizerRect(WebWidget* webwidget,
[email protected]b3f2b912009-04-09 16:18:52686 WebRect* rect) {
[email protected]fb63b722009-02-19 18:05:14687 *rect = resizer_rect_;
[email protected]c04b6362008-11-21 18:54:19688}
689
initial.commit09911bf2008-07-26 23:55:29690void RenderWidget::OnImeSetInputMode(bool is_active) {
[email protected]c4bb35a2008-10-31 17:54:03691 // To prevent this renderer process from sending unnecessary IPC messages to
692 // a browser process, we permit the renderer process to send IPC messages
693 // only during the IME attached to the browser process is active.
initial.commit09911bf2008-07-26 23:55:29694 ime_is_active_ = is_active;
initial.commit09911bf2008-07-26 23:55:29695}
696
697void RenderWidget::OnImeSetComposition(int string_type,
698 int cursor_position,
699 int target_start, int target_end,
700 const std::wstring& ime_string) {
701 if (webwidget_) {
[email protected]9f23f592008-11-17 08:36:34702 ime_control_busy_ = true;
initial.commit09911bf2008-07-26 23:55:29703 webwidget_->ImeSetComposition(string_type, cursor_position,
704 target_start, target_end,
[email protected]34f6bc12008-11-06 07:40:53705 ime_string);
[email protected]9f23f592008-11-17 08:36:34706 ime_control_busy_ = false;
initial.commit09911bf2008-07-26 23:55:29707 }
708}
709
[email protected]ec7dc112008-08-06 05:30:12710void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) {
711 // During shutdown we can just ignore this message.
712 if (!webwidget_)
713 return;
714
715 set_next_paint_is_repaint_ack();
716 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height());
717 DidInvalidateRect(webwidget_, repaint_rect);
718}
719
[email protected]07f953332009-03-25 04:31:11720void RenderWidget::OnSetTextDirection(int direction) {
721 if (!webwidget_)
722 return;
723
724 WebTextDirection new_direction = static_cast<WebTextDirection>(direction);
725 if (new_direction == WEB_TEXT_DIRECTION_DEFAULT ||
726 new_direction == WEB_TEXT_DIRECTION_LTR ||
727 new_direction == WEB_TEXT_DIRECTION_RTL) {
728 webwidget_->SetTextDirection(new_direction);
729 } else {
730 NOTREACHED();
731 }
732}
733
[email protected]699ab0d2009-04-23 23:19:14734void RenderWidget::SetBackground(const SkBitmap& background) {
735 background_ = background;
736 // Generate a full repaint.
737 DidInvalidateRect(webwidget_, gfx::Rect(size_.width(), size_.height()));
738}
739
[email protected]674741932009-02-04 23:44:46740bool RenderWidget::next_paint_is_resize_ack() const {
741 return ViewHostMsg_PaintRect_Flags::is_resize_ack(next_paint_flags_);
742}
743
744bool RenderWidget::next_paint_is_restore_ack() const {
745 return ViewHostMsg_PaintRect_Flags::is_restore_ack(next_paint_flags_);
746}
747
748void RenderWidget::set_next_paint_is_resize_ack() {
749 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESIZE_ACK;
750}
751
752void RenderWidget::set_next_paint_is_restore_ack() {
753 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESTORE_ACK;
754}
755
756void RenderWidget::set_next_paint_is_repaint_ack() {
757 next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_REPAINT_ACK;
758}
759
initial.commit09911bf2008-07-26 23:55:29760void RenderWidget::UpdateIME() {
761 // If a browser process does not have IMEs, its IMEs are not active, or there
762 // are not any attached widgets.
763 // a renderer process does not have to retrieve information of the focused
764 // control or send notification messages to a browser process.
765 if (!ime_is_active_) {
766 return;
767 }
[email protected]34f6bc12008-11-06 07:40:53768 // Retrieve the caret position from the focused widget and verify we should
769 // enabled IMEs attached to the browser process.
770 bool enable_ime = false;
[email protected]b3f2b912009-04-09 16:18:52771 WebRect caret_rect;
[email protected]34f6bc12008-11-06 07:40:53772 if (!webwidget_ ||
[email protected]8dcfd8c92009-02-20 16:15:12773 !webwidget_->ImeUpdateStatus(&enable_ime, &caret_rect)) {
initial.commit09911bf2008-07-26 23:55:29774 // There are not any editable widgets attached to this process.
775 // We should disable the IME to prevent it from sending CJK strings to
776 // non-editable widgets.
777 ime_control_updated_ = true;
778 ime_control_new_state_ = false;
779 }
[email protected]9f23f592008-11-17 08:36:34780 if (ime_control_new_state_ != enable_ime) {
781 ime_control_updated_ = true;
782 ime_control_new_state_ = enable_ime;
783 }
initial.commit09911bf2008-07-26 23:55:29784 if (ime_control_updated_) {
785 // The input focus has been changed.
786 // Compare the current state with the updated state and choose actions.
787 if (ime_control_enable_ime_) {
788 if (ime_control_new_state_) {
789 // Case 1: a text input -> another text input
790 // Complete the current composition and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53791 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
792 IME_COMPLETE_COMPOSITION,
793 caret_rect));
initial.commit09911bf2008-07-26 23:55:29794 } else {
795 // Case 2: a text input -> a password input (or a static control)
796 // Complete the current composition and disable the IME.
[email protected]34f6bc12008-11-06 07:40:53797 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_DISABLE,
798 caret_rect));
initial.commit09911bf2008-07-26 23:55:29799 }
800 } else {
801 if (ime_control_new_state_) {
802 // Case 3: a password input (or a static control) -> a text input
803 // Enable the IME and notify the caret position.
[email protected]34f6bc12008-11-06 07:40:53804 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(),
805 IME_COMPLETE_COMPOSITION,
806 caret_rect));
initial.commit09911bf2008-07-26 23:55:29807 } else {
808 // Case 4: a password input (or a static contol) -> another password
809 // input (or another static control).
810 // The IME has been already disabled and we don't have to do anything.
811 }
812 }
813 } else {
814 // The input focus is not changed.
815 // Notify the caret position to a browser process only if it is changed.
816 if (ime_control_enable_ime_) {
[email protected]b3f2b912009-04-09 16:18:52817 if (caret_rect.x != ime_control_x_ ||
818 caret_rect.y != ime_control_y_) {
[email protected]34f6bc12008-11-06 07:40:53819 Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), IME_MOVE_WINDOWS,
820 caret_rect));
initial.commit09911bf2008-07-26 23:55:29821 }
822 }
823 }
824 // Save the updated IME status to prevent from sending the same IPC messages.
825 ime_control_updated_ = false;
826 ime_control_enable_ime_ = ime_control_new_state_;
[email protected]b3f2b912009-04-09 16:18:52827 ime_control_x_ = caret_rect.x;
828 ime_control_y_ = caret_rect.y;
initial.commit09911bf2008-07-26 23:55:29829}
830
831void RenderWidget::DidMove(WebWidget* webwidget,
832 const WebPluginGeometry& move) {
833 size_t i = 0;
834 for (; i < plugin_window_moves_.size(); ++i) {
835 if (plugin_window_moves_[i].window == move.window) {
836 plugin_window_moves_[i] = move;
837 break;
838 }
839 }
840
841 if (i == plugin_window_moves_.size())
842 plugin_window_moves_.push_back(move);
843}
[email protected]12456fa2009-04-01 23:07:19844
845WebScreenInfo RenderWidget::GetScreenInfo(WebWidget* webwidget) {
846 WebScreenInfo results;
847 RenderThread::current()->Send(
848 new ViewHostMsg_GetScreenInfo(host_window_, &results));
849 return results;
850}