| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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. | |
| 4 | |
| 5 #include "chrome/renderer/render_widget.h" | |
| 6 | |
| 7 #include "app/surface/transport_dib.h" | |
| 8 #include "base/command_line.h" | |
| 9 #include "base/logging.h" | |
| 10 #include "base/message_loop.h" | |
| 11 #include "base/metrics/histogram.h" | |
| 12 #include "base/scoped_ptr.h" | |
| 13 #include "build/build_config.h" | |
| 14 #include "chrome/common/chrome_switches.h" | |
| 15 #include "chrome/common/render_messages.h" | |
| 16 #include "chrome/common/render_messages_params.h" | |
| 17 #include "chrome/renderer/render_process.h" | |
| 18 #include "chrome/renderer/render_thread.h" | |
| 19 #include "content/renderer/renderer_webkitclient_impl.h" | |
| 20 #include "gpu/common/gpu_trace_event.h" | |
| 21 #include "ipc/ipc_sync_message.h" | |
| 22 #include "skia/ext/platform_canvas.h" | |
| 23 #include "third_party/skia/include/core/SkShader.h" | |
| 24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" | |
| 25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h" | |
| 26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenuInfo.h" | |
| 27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h" | |
| 28 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" | |
| 29 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" | |
| 30 #include "ui/gfx/point.h" | |
| 31 #include "ui/gfx/size.h" | |
| 32 #include "webkit/glue/webkit_glue.h" | |
| 33 #include "webkit/plugins/npapi/webplugin.h" | |
| 34 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" | |
| 35 | |
| 36 #if defined(OS_POSIX) | |
| 37 #include "ipc/ipc_channel_posix.h" | |
| 38 #include "third_party/skia/include/core/SkPixelRef.h" | |
| 39 #include "third_party/skia/include/core/SkMallocPixelRef.h" | |
| 40 #endif // defined(OS_POSIX) | |
| 41 | |
| 42 #include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" | |
| 43 | |
| 44 using WebKit::WebCompositionUnderline; | |
| 45 using WebKit::WebCursorInfo; | |
| 46 using WebKit::WebInputEvent; | |
| 47 using WebKit::WebMouseEvent; | |
| 48 using WebKit::WebNavigationPolicy; | |
| 49 using WebKit::WebPopupMenu; | |
| 50 using WebKit::WebPopupMenuInfo; | |
| 51 using WebKit::WebPopupType; | |
| 52 using WebKit::WebRect; | |
| 53 using WebKit::WebScreenInfo; | |
| 54 using WebKit::WebSize; | |
| 55 using WebKit::WebTextDirection; | |
| 56 using WebKit::WebTextInputType; | |
| 57 using WebKit::WebVector; | |
| 58 using WebKit::WebWidget; | |
| 59 | |
| 60 RenderWidget::RenderWidget(RenderThreadBase* render_thread, | |
| 61 WebKit::WebPopupType popup_type) | |
| 62 : routing_id_(MSG_ROUTING_NONE), | |
| 63 webwidget_(NULL), | |
| 64 opener_id_(MSG_ROUTING_NONE), | |
| 65 render_thread_(render_thread), | |
| 66 host_window_(0), | |
| 67 current_paint_buf_(NULL), | |
| 68 next_paint_flags_(0), | |
| 69 update_reply_pending_(false), | |
| 70 did_show_(false), | |
| 71 is_hidden_(false), | |
| 72 needs_repainting_on_restore_(false), | |
| 73 has_focus_(false), | |
| 74 handling_input_event_(false), | |
| 75 closing_(false), | |
| 76 input_method_is_active_(false), | |
| 77 text_input_type_(WebKit::WebTextInputTypeNone), | |
| 78 popup_type_(popup_type), | |
| 79 pending_window_rect_count_(0), | |
| 80 suppress_next_char_events_(false), | |
| 81 is_accelerated_compositing_active_(false), | |
| 82 animation_update_pending_(false), | |
| 83 animation_task_posted_(false) { | |
| 84 RenderProcess::current()->AddRefProcess(); | |
| 85 DCHECK(render_thread_); | |
| 86 } | |
| 87 | |
| 88 RenderWidget::~RenderWidget() { | |
| 89 DCHECK(!webwidget_) << "Leaking our WebWidget!"; | |
| 90 if (current_paint_buf_) { | |
| 91 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); | |
| 92 current_paint_buf_ = NULL; | |
| 93 } | |
| 94 RenderProcess::current()->ReleaseProcess(); | |
| 95 } | |
| 96 | |
| 97 // static | |
| 98 RenderWidget* RenderWidget::Create(int32 opener_id, | |
| 99 RenderThreadBase* render_thread, | |
| 100 WebKit::WebPopupType popup_type) { | |
| 101 DCHECK(opener_id != MSG_ROUTING_NONE); | |
| 102 scoped_refptr<RenderWidget> widget(new RenderWidget(render_thread, | |
| 103 popup_type)); | |
| 104 widget->Init(opener_id); // adds reference | |
| 105 return widget; | |
| 106 } | |
| 107 | |
| 108 // static | |
| 109 WebWidget* RenderWidget::CreateWebWidget(RenderWidget* render_widget) { | |
| 110 switch (render_widget->popup_type_) { | |
| 111 case WebKit::WebPopupTypeNone: // Nothing to create. | |
| 112 break; | |
| 113 case WebKit::WebPopupTypeSelect: | |
| 114 case WebKit::WebPopupTypeSuggestion: | |
| 115 return WebPopupMenu::create(render_widget); | |
| 116 default: | |
| 117 NOTREACHED(); | |
| 118 } | |
| 119 return NULL; | |
| 120 } | |
| 121 | |
| 122 void RenderWidget::Init(int32 opener_id) { | |
| 123 DoInit(opener_id, | |
| 124 RenderWidget::CreateWebWidget(this), | |
| 125 new ViewHostMsg_CreateWidget(opener_id, popup_type_, &routing_id_)); | |
| 126 } | |
| 127 | |
| 128 void RenderWidget::DoInit(int32 opener_id, | |
| 129 WebWidget* web_widget, | |
| 130 IPC::SyncMessage* create_widget_message) { | |
| 131 DCHECK(!webwidget_); | |
| 132 | |
| 133 if (opener_id != MSG_ROUTING_NONE) | |
| 134 opener_id_ = opener_id; | |
| 135 | |
| 136 webwidget_ = web_widget; | |
| 137 | |
| 138 bool result = render_thread_->Send(create_widget_message); | |
| 139 if (result) { | |
| 140 render_thread_->AddRoute(routing_id_, this); | |
| 141 // Take a reference on behalf of the RenderThread. This will be balanced | |
| 142 // when we receive ViewMsg_Close. | |
| 143 AddRef(); | |
| 144 } else { | |
| 145 DCHECK(false); | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 // This is used to complete pending inits and non-pending inits. For non- | |
| 150 // pending cases, the parent will be the same as the current parent. This | |
| 151 // indicates we do not need to reparent or anything. | |
| 152 void RenderWidget::CompleteInit(gfx::NativeViewId parent_hwnd) { | |
| 153 DCHECK(routing_id_ != MSG_ROUTING_NONE); | |
| 154 | |
| 155 host_window_ = parent_hwnd; | |
| 156 | |
| 157 Send(new ViewHostMsg_RenderViewReady(routing_id_)); | |
| 158 } | |
| 159 | |
| 160 bool RenderWidget::OnMessageReceived(const IPC::Message& message) { | |
| 161 bool handled = true; | |
| 162 IPC_BEGIN_MESSAGE_MAP(RenderWidget, message) | |
| 163 IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose) | |
| 164 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck) | |
| 165 IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize) | |
| 166 IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden) | |
| 167 IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored) | |
| 168 IPC_MESSAGE_HANDLER(ViewMsg_UpdateRect_ACK, OnUpdateRectAck) | |
| 169 IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent) | |
| 170 IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost) | |
| 171 IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus) | |
| 172 IPC_MESSAGE_HANDLER(ViewMsg_SetInputMethodActive, OnSetInputMethodActive) | |
| 173 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition) | |
| 174 IPC_MESSAGE_HANDLER(ViewMsg_ImeConfirmComposition, OnImeConfirmComposition) | |
| 175 IPC_MESSAGE_HANDLER(ViewMsg_PaintAtSize, OnMsgPaintAtSize) | |
| 176 IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint) | |
| 177 IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection) | |
| 178 IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck) | |
| 179 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 180 IPC_END_MESSAGE_MAP() | |
| 181 return handled; | |
| 182 } | |
| 183 | |
| 184 bool RenderWidget::Send(IPC::Message* message) { | |
| 185 // Don't send any messages after the browser has told us to close. | |
| 186 if (closing_) { | |
| 187 delete message; | |
| 188 return false; | |
| 189 } | |
| 190 | |
| 191 // If given a messsage without a routing ID, then assign our routing ID. | |
| 192 if (message->routing_id() == MSG_ROUTING_NONE) | |
| 193 message->set_routing_id(routing_id_); | |
| 194 | |
| 195 return render_thread_->Send(message); | |
| 196 } | |
| 197 | |
| 198 // Got a response from the browser after the renderer decided to create a new | |
| 199 // view. | |
| 200 void RenderWidget::OnCreatingNewAck(gfx::NativeViewId parent) { | |
| 201 DCHECK(routing_id_ != MSG_ROUTING_NONE); | |
| 202 | |
| 203 CompleteInit(parent); | |
| 204 } | |
| 205 | |
| 206 void RenderWidget::OnClose() { | |
| 207 if (closing_) | |
| 208 return; | |
| 209 closing_ = true; | |
| 210 | |
| 211 // Browser correspondence is no longer needed at this point. | |
| 212 if (routing_id_ != MSG_ROUTING_NONE) { | |
| 213 render_thread_->RemoveRoute(routing_id_); | |
| 214 SetHidden(false); | |
| 215 } | |
| 216 | |
| 217 // If there is a Send call on the stack, then it could be dangerous to close | |
| 218 // now. Post a task that only gets invoked when there are no nested message | |
| 219 // loops. | |
| 220 MessageLoop::current()->PostNonNestableTask(FROM_HERE, | |
| 221 NewRunnableMethod(this, &RenderWidget::Close)); | |
| 222 | |
| 223 // Balances the AddRef taken when we called AddRoute. | |
| 224 Release(); | |
| 225 } | |
| 226 | |
| 227 void RenderWidget::OnResize(const gfx::Size& new_size, | |
| 228 const gfx::Rect& resizer_rect) { | |
| 229 // During shutdown we can just ignore this message. | |
| 230 if (!webwidget_) | |
| 231 return; | |
| 232 | |
| 233 // We shouldn't be asked to resize to our current size. | |
| 234 DCHECK(size_ != new_size || resizer_rect_ != resizer_rect); | |
| 235 | |
| 236 // Remember the rect where the resize corner will be drawn. | |
| 237 resizer_rect_ = resizer_rect; | |
| 238 | |
| 239 if (size_ == new_size) | |
| 240 return; | |
| 241 | |
| 242 // TODO(darin): We should not need to reset this here. | |
| 243 SetHidden(false); | |
| 244 needs_repainting_on_restore_ = false; | |
| 245 | |
| 246 size_ = new_size; | |
| 247 | |
| 248 // We should not be sent a Resize message if we have not ACK'd the previous | |
| 249 DCHECK(!next_paint_is_resize_ack()); | |
| 250 | |
| 251 paint_aggregator_.ClearPendingUpdate(); | |
| 252 | |
| 253 // When resizing, we want to wait to paint before ACK'ing the resize. This | |
| 254 // ensures that we only resize as fast as we can paint. We only need to send | |
| 255 // an ACK if we are resized to a non-empty rect. | |
| 256 webwidget_->resize(new_size); | |
| 257 if (!new_size.IsEmpty()) { | |
| 258 if (!is_accelerated_compositing_active_) { | |
| 259 // Resize should have caused an invalidation of the entire view. | |
| 260 DCHECK(paint_aggregator_.HasPendingUpdate()); | |
| 261 } | |
| 262 | |
| 263 // We will send the Resize_ACK flag once we paint again. | |
| 264 set_next_paint_is_resize_ack(); | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 void RenderWidget::OnWasHidden() { | |
| 269 // Go into a mode where we stop generating paint and scrolling events. | |
| 270 SetHidden(true); | |
| 271 } | |
| 272 | |
| 273 void RenderWidget::OnWasRestored(bool needs_repainting) { | |
| 274 // During shutdown we can just ignore this message. | |
| 275 if (!webwidget_) | |
| 276 return; | |
| 277 | |
| 278 // See OnWasHidden | |
| 279 SetHidden(false); | |
| 280 | |
| 281 if (!needs_repainting && !needs_repainting_on_restore_) | |
| 282 return; | |
| 283 needs_repainting_on_restore_ = false; | |
| 284 | |
| 285 // Tag the next paint as a restore ack, which is picked up by | |
| 286 // DoDeferredUpdate when it sends out the next PaintRect message. | |
| 287 set_next_paint_is_restore_ack(); | |
| 288 | |
| 289 // Generate a full repaint. | |
| 290 if (!is_accelerated_compositing_active_) { | |
| 291 didInvalidateRect(gfx::Rect(size_.width(), size_.height())); | |
| 292 } else { | |
| 293 scheduleComposite(); | |
| 294 } | |
| 295 } | |
| 296 | |
| 297 void RenderWidget::OnRequestMoveAck() { | |
| 298 DCHECK(pending_window_rect_count_); | |
| 299 pending_window_rect_count_--; | |
| 300 } | |
| 301 | |
| 302 void RenderWidget::OnUpdateRectAck() { | |
| 303 DCHECK(update_reply_pending()); | |
| 304 update_reply_pending_ = false; | |
| 305 | |
| 306 // If we sent an UpdateRect message with a zero-sized bitmap, then we should | |
| 307 // have no current paint buffer. | |
| 308 if (current_paint_buf_) { | |
| 309 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); | |
| 310 current_paint_buf_ = NULL; | |
| 311 } | |
| 312 | |
| 313 // Notify subclasses. | |
| 314 DidFlushPaint(); | |
| 315 | |
| 316 // Continue painting if necessary... | |
| 317 CallDoDeferredUpdate(); | |
| 318 } | |
| 319 | |
| 320 void RenderWidget::OnHandleInputEvent(const IPC::Message& message) { | |
| 321 void* iter = NULL; | |
| 322 | |
| 323 const char* data; | |
| 324 int data_length; | |
| 325 handling_input_event_ = true; | |
| 326 if (!message.ReadData(&iter, &data, &data_length)) { | |
| 327 handling_input_event_ = false; | |
| 328 return; | |
| 329 } | |
| 330 | |
| 331 const WebInputEvent* input_event = | |
| 332 reinterpret_cast<const WebInputEvent*>(data); | |
| 333 | |
| 334 bool is_keyboard_shortcut = false; | |
| 335 // is_keyboard_shortcut flag is only available for RawKeyDown events. | |
| 336 if (input_event->type == WebInputEvent::RawKeyDown) | |
| 337 message.ReadBool(&iter, &is_keyboard_shortcut); | |
| 338 | |
| 339 bool processed = false; | |
| 340 if (input_event->type != WebInputEvent::Char || !suppress_next_char_events_) { | |
| 341 suppress_next_char_events_ = false; | |
| 342 if (webwidget_) | |
| 343 processed = webwidget_->handleInputEvent(*input_event); | |
| 344 } | |
| 345 | |
| 346 // If this RawKeyDown event corresponds to a browser keyboard shortcut and | |
| 347 // it's not processed by webkit, then we need to suppress the upcoming Char | |
| 348 // events. | |
| 349 if (!processed && is_keyboard_shortcut) | |
| 350 suppress_next_char_events_ = true; | |
| 351 | |
| 352 IPC::Message* response = new ViewHostMsg_HandleInputEvent_ACK(routing_id_); | |
| 353 response->WriteInt(input_event->type); | |
| 354 response->WriteBool(processed); | |
| 355 | |
| 356 if ((input_event->type == WebInputEvent::MouseMove || | |
| 357 input_event->type == WebInputEvent::MouseWheel || | |
| 358 input_event->type == WebInputEvent::TouchMove) && | |
| 359 paint_aggregator_.HasPendingUpdate()) { | |
| 360 // We want to rate limit the input events in this case, so we'll wait for | |
| 361 // painting to finish before ACKing this message. | |
| 362 if (pending_input_event_ack_.get()) { | |
| 363 // As two different kinds of events could cause us to postpone an ack | |
| 364 // we send it now, if we have one pending. The Browser should never | |
| 365 // send us the same kind of event we are delaying the ack for. | |
| 366 Send(pending_input_event_ack_.release()); | |
| 367 } | |
| 368 pending_input_event_ack_.reset(response); | |
| 369 } else { | |
| 370 Send(response); | |
| 371 } | |
| 372 | |
| 373 handling_input_event_ = false; | |
| 374 | |
| 375 if (WebInputEvent::isKeyboardEventType(input_event->type)) | |
| 376 DidHandleKeyEvent(); | |
| 377 if (WebInputEvent::isMouseEventType(input_event->type)) | |
| 378 DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event))); | |
| 379 } | |
| 380 | |
| 381 void RenderWidget::OnMouseCaptureLost() { | |
| 382 if (webwidget_) | |
| 383 webwidget_->mouseCaptureLost(); | |
| 384 } | |
| 385 | |
| 386 void RenderWidget::OnSetFocus(bool enable) { | |
| 387 has_focus_ = enable; | |
| 388 if (webwidget_) | |
| 389 webwidget_->setFocus(enable); | |
| 390 } | |
| 391 | |
| 392 void RenderWidget::ClearFocus() { | |
| 393 // We may have got the focus from the browser before this gets processed, in | |
| 394 // which case we do not want to unfocus ourself. | |
| 395 if (!has_focus_ && webwidget_) | |
| 396 webwidget_->setFocus(false); | |
| 397 } | |
| 398 | |
| 399 void RenderWidget::PaintRect(const gfx::Rect& rect, | |
| 400 const gfx::Point& canvas_origin, | |
| 401 skia::PlatformCanvas* canvas) { | |
| 402 | |
| 403 canvas->save(); | |
| 404 | |
| 405 // Bring the canvas into the coordinate system of the paint rect. | |
| 406 canvas->translate(static_cast<SkScalar>(-canvas_origin.x()), | |
| 407 static_cast<SkScalar>(-canvas_origin.y())); | |
| 408 | |
| 409 // If there is a custom background, tile it. | |
| 410 if (!background_.empty()) { | |
| 411 SkPaint paint; | |
| 412 SkShader* shader = SkShader::CreateBitmapShader(background_, | |
| 413 SkShader::kRepeat_TileMode, | |
| 414 SkShader::kRepeat_TileMode); | |
| 415 paint.setShader(shader)->unref(); | |
| 416 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); | |
| 417 canvas->drawPaint(paint); | |
| 418 } | |
| 419 | |
| 420 // First see if this rect is a plugin that can paint itself faster. | |
| 421 TransportDIB* optimized_dib = NULL; | |
| 422 gfx::Rect optimized_copy_rect, optimized_copy_location; | |
| 423 webkit::ppapi::PluginInstance* optimized_instance = | |
| 424 GetBitmapForOptimizedPluginPaint(rect, &optimized_dib, | |
| 425 &optimized_copy_location, | |
| 426 &optimized_copy_rect); | |
| 427 if (optimized_instance) { | |
| 428 // This plugin can be optimize-painted and we can just ask it to paint | |
| 429 // itself. We don't actually need the TransportDIB in this case. | |
| 430 // | |
| 431 // This is an optimization for PPAPI plugins that know they're on top of | |
| 432 // the page content. If this rect is inside such a plugin, we can save some | |
| 433 // time and avoid re-rendering the page content which we know will be | |
| 434 // covered by the plugin later (this time can be significant, especially | |
| 435 // for a playing movie that is invalidating a lot). | |
| 436 // | |
| 437 // In the plugin movie case, hopefully the similar call to | |
| 438 // GetBitmapForOptimizedPluginPaint in DoDeferredUpdate handles the | |
| 439 // painting, because that avoids copying the plugin image to a different | |
| 440 // paint rect. Unfortunately, if anything on the page is animating other | |
| 441 // than the movie, it break this optimization since the union of the | |
| 442 // invalid regions will be larger than the plugin. | |
| 443 // | |
| 444 // This code optimizes that case, where we can still avoid painting in | |
| 445 // WebKit and filling the background (which can be slow) and just painting | |
| 446 // the plugin. Unlike the DoDeferredUpdate case, an extra copy is still | |
| 447 // required. | |
| 448 optimized_instance->Paint(webkit_glue::ToWebCanvas(canvas), | |
| 449 optimized_copy_location, rect); | |
| 450 } else { | |
| 451 // Normal painting case. | |
| 452 webwidget_->paint(webkit_glue::ToWebCanvas(canvas), rect); | |
| 453 | |
| 454 // Flush to underlying bitmap. TODO(darin): is this needed? | |
| 455 canvas->getTopPlatformDevice().accessBitmap(false); | |
| 456 } | |
| 457 | |
| 458 PaintDebugBorder(rect, canvas); | |
| 459 canvas->restore(); | |
| 460 } | |
| 461 | |
| 462 void RenderWidget::PaintDebugBorder(const gfx::Rect& rect, | |
| 463 skia::PlatformCanvas* canvas) { | |
| 464 static bool kPaintBorder = | |
| 465 CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowPaintRects); | |
| 466 if (!kPaintBorder) | |
| 467 return; | |
| 468 | |
| 469 // Cycle through these colors to help distinguish new paint rects. | |
| 470 const SkColor colors[] = { | |
| 471 SkColorSetARGB(0x3F, 0xFF, 0, 0), | |
| 472 SkColorSetARGB(0x3F, 0xFF, 0, 0xFF), | |
| 473 SkColorSetARGB(0x3F, 0, 0, 0xFF), | |
| 474 }; | |
| 475 static int color_selector = 0; | |
| 476 | |
| 477 SkPaint paint; | |
| 478 paint.setStyle(SkPaint::kStroke_Style); | |
| 479 paint.setColor(colors[color_selector++ % arraysize(colors)]); | |
| 480 paint.setStrokeWidth(1); | |
| 481 | |
| 482 SkIRect irect; | |
| 483 irect.set(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1); | |
| 484 canvas->drawIRect(irect, paint); | |
| 485 } | |
| 486 | |
| 487 void RenderWidget::AnimationCallback() { | |
| 488 animation_task_posted_ = false; | |
| 489 if (!animation_update_pending_) | |
| 490 return; | |
| 491 if (!animation_floor_time_.is_null()) { | |
| 492 // Record when we fired (according to base::Time::Now()) relative to when | |
| 493 // we posted the task to quantify how much the base::Time/base::TimeTicks | |
| 494 // skew is affecting animations. | |
| 495 base::TimeDelta animation_callback_delay = base::Time::Now() - | |
| 496 (animation_floor_time_ - base::TimeDelta::FromMilliseconds(16)); | |
| 497 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.AnimationCallbackDelayTime", | |
| 498 animation_callback_delay, | |
| 499 base::TimeDelta::FromMilliseconds(0), | |
| 500 base::TimeDelta::FromMilliseconds(30), | |
| 501 25); | |
| 502 } | |
| 503 CallDoDeferredUpdate(); | |
| 504 } | |
| 505 | |
| 506 void RenderWidget::AnimateIfNeeded() { | |
| 507 if (!animation_update_pending_) | |
| 508 return; | |
| 509 base::Time now = base::Time::Now(); | |
| 510 if (now >= animation_floor_time_) { | |
| 511 animation_floor_time_ = now + base::TimeDelta::FromMilliseconds(16); | |
| 512 // Set a timer to call us back after 16ms (targetting 60FPS) before | |
| 513 // running animation callbacks so that if a callback requests another | |
| 514 // we'll be sure to run it at the proper time. | |
| 515 MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod( | |
| 516 this, &RenderWidget::AnimationCallback), 16); | |
| 517 animation_task_posted_ = true; | |
| 518 animation_update_pending_ = false; | |
| 519 // Explicitly pump the WebCore Timer queue to avoid starvation on OS X. | |
| 520 // See crbug.com/71735. | |
| 521 // TODO(jamesr) Remove this call once crbug.com/72007 is fixed. | |
| 522 RenderThread::current()->GetWebKitClientImpl()->DoTimeout(); | |
| 523 webwidget_->animate(); | |
| 524 return; | |
| 525 } | |
| 526 if (animation_task_posted_) | |
| 527 return; | |
| 528 // This code uses base::Time::Now() to calculate the floor and next fire | |
| 529 // time because javascript's Date object uses base::Time::Now(). The | |
| 530 // message loop uses base::TimeTicks, which on windows can have a | |
| 531 // different granularity than base::Time. | |
| 532 // The upshot of all this is that this function might be called before | |
| 533 // base::Time::Now() has advanced past the animation_floor_time_. To | |
| 534 // avoid exposing this delay to javascript, we keep posting delayed | |
| 535 // tasks until base::Time::Now() has advanced far enough. | |
| 536 int64 delay = (animation_floor_time_ - now).InMillisecondsRoundedUp(); | |
| 537 animation_task_posted_ = true; | |
| 538 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
| 539 NewRunnableMethod(this, &RenderWidget::AnimationCallback), delay); | |
| 540 } | |
| 541 | |
| 542 void RenderWidget::CallDoDeferredUpdate() { | |
| 543 DoDeferredUpdate(); | |
| 544 | |
| 545 if (pending_input_event_ack_.get()) | |
| 546 Send(pending_input_event_ack_.release()); | |
| 547 } | |
| 548 | |
| 549 void RenderWidget::DoDeferredUpdate() { | |
| 550 GPU_TRACE_EVENT0("render_widget", "DoDeferredUpdate"); | |
| 551 | |
| 552 if (!webwidget_ || update_reply_pending()) | |
| 553 return; | |
| 554 | |
| 555 // Suppress updating when we are hidden. | |
| 556 if (is_hidden_ || size_.IsEmpty()) { | |
| 557 paint_aggregator_.ClearPendingUpdate(); | |
| 558 needs_repainting_on_restore_ = true; | |
| 559 return; | |
| 560 } | |
| 561 | |
| 562 AnimateIfNeeded(); | |
| 563 | |
| 564 // Layout may generate more invalidation. It may also enable the | |
| 565 // GPU acceleration, so make sure to run layout before we send the | |
| 566 // GpuRenderingActivated message. | |
| 567 webwidget_->layout(); | |
| 568 | |
| 569 // Suppress painting if nothing is dirty. This has to be done after updating | |
| 570 // animations running layout as these may generate further invalidations. | |
| 571 if (!paint_aggregator_.HasPendingUpdate()) | |
| 572 return; | |
| 573 | |
| 574 // OK, save the pending update to a local since painting may cause more | |
| 575 // invalidation. Some WebCore rendering objects only layout when painted. | |
| 576 PaintAggregator::PendingUpdate update; | |
| 577 paint_aggregator_.PopPendingUpdate(&update); | |
| 578 | |
| 579 gfx::Rect scroll_damage = update.GetScrollDamage(); | |
| 580 gfx::Rect bounds = update.GetPaintBounds().Union(scroll_damage); | |
| 581 | |
| 582 // A plugin may be able to do an optimized paint. First check this, in which | |
| 583 // case we can skip all of the bitmap generation and regular paint code. | |
| 584 // This optimization allows PPAPI plugins that declare themselves on top of | |
| 585 // the page (like a traditional windowed plugin) to be able to animate (think | |
| 586 // movie playing) without repeatedly re-painting the page underneath, or | |
| 587 // copying the plugin backing store (since we can send the plugin's backing | |
| 588 // store directly to the browser). | |
| 589 // | |
| 590 // This optimization only works when the entire invalid region is contained | |
| 591 // within the plugin. There is a related optimization in PaintRect for the | |
| 592 // case where there may be multiple invalid regions. | |
| 593 TransportDIB::Id dib_id = TransportDIB::Id(); | |
| 594 TransportDIB* dib = NULL; | |
| 595 std::vector<gfx::Rect> copy_rects; | |
| 596 gfx::Rect optimized_copy_rect, optimized_copy_location; | |
| 597 if (update.scroll_rect.IsEmpty() && | |
| 598 !is_accelerated_compositing_active_ && | |
| 599 GetBitmapForOptimizedPluginPaint(bounds, &dib, &optimized_copy_location, | |
| 600 &optimized_copy_rect)) { | |
| 601 // Only update the part of the plugin that actually changed. | |
| 602 optimized_copy_rect = optimized_copy_rect.Intersect(bounds); | |
| 603 bounds = optimized_copy_location; | |
| 604 copy_rects.push_back(optimized_copy_rect); | |
| 605 dib_id = dib->id(); | |
| 606 } else if (!is_accelerated_compositing_active_) { | |
| 607 // Compute a buffer for painting and cache it. | |
| 608 scoped_ptr<skia::PlatformCanvas> canvas( | |
| 609 RenderProcess::current()->GetDrawingCanvas(¤t_paint_buf_, | |
| 610 bounds)); | |
| 611 if (!canvas.get()) { | |
| 612 NOTREACHED(); | |
| 613 return; | |
| 614 } | |
| 615 | |
| 616 // We may get back a smaller canvas than we asked for. | |
| 617 // TODO(darin): This seems like it could cause painting problems! | |
| 618 DCHECK_EQ(bounds.width(), canvas->getDevice()->width()); | |
| 619 DCHECK_EQ(bounds.height(), canvas->getDevice()->height()); | |
| 620 bounds.set_width(canvas->getDevice()->width()); | |
| 621 bounds.set_height(canvas->getDevice()->height()); | |
| 622 | |
| 623 HISTOGRAM_COUNTS_100("MPArch.RW_PaintRectCount", update.paint_rects.size()); | |
| 624 | |
| 625 // The scroll damage is just another rectangle to paint and copy. | |
| 626 copy_rects.swap(update.paint_rects); | |
| 627 if (!scroll_damage.IsEmpty()) | |
| 628 copy_rects.push_back(scroll_damage); | |
| 629 | |
| 630 for (size_t i = 0; i < copy_rects.size(); ++i) | |
| 631 PaintRect(copy_rects[i], bounds.origin(), canvas.get()); | |
| 632 | |
| 633 dib_id = current_paint_buf_->id(); | |
| 634 } else { // Accelerated compositing path | |
| 635 // Begin painting. | |
| 636 webwidget_->composite(false); | |
| 637 } | |
| 638 | |
| 639 // sending an ack to browser process that the paint is complete... | |
| 640 ViewHostMsg_UpdateRect_Params params; | |
| 641 params.bitmap = dib_id; | |
| 642 params.bitmap_rect = bounds; | |
| 643 params.dx = update.scroll_delta.x(); | |
| 644 params.dy = update.scroll_delta.y(); | |
| 645 if (is_accelerated_compositing_active_) { | |
| 646 // If painting is done via the gpu process then we clear out all damage | |
| 647 // rects to save the browser process from doing unecessary work. | |
| 648 params.scroll_rect = gfx::Rect(); | |
| 649 params.copy_rects.clear(); | |
| 650 } else { | |
| 651 params.scroll_rect = update.scroll_rect; | |
| 652 params.copy_rects.swap(copy_rects); // TODO(darin): clip to bounds? | |
| 653 } | |
| 654 params.view_size = size_; | |
| 655 params.resizer_rect = resizer_rect_; | |
| 656 params.plugin_window_moves.swap(plugin_window_moves_); | |
| 657 params.flags = next_paint_flags_; | |
| 658 params.scroll_offset = GetScrollOffset(); | |
| 659 | |
| 660 update_reply_pending_ = true; | |
| 661 Send(new ViewHostMsg_UpdateRect(routing_id_, params)); | |
| 662 next_paint_flags_ = 0; | |
| 663 | |
| 664 UpdateInputMethod(); | |
| 665 | |
| 666 // Let derived classes know we've painted. | |
| 667 DidInitiatePaint(); | |
| 668 } | |
| 669 | |
| 670 /////////////////////////////////////////////////////////////////////////////// | |
| 671 // WebWidgetClient | |
| 672 | |
| 673 void RenderWidget::didInvalidateRect(const WebRect& rect) { | |
| 674 // We only want one pending DoDeferredUpdate call at any time... | |
| 675 bool update_pending = paint_aggregator_.HasPendingUpdate(); | |
| 676 | |
| 677 // The invalidated rect might be outside the bounds of the view. | |
| 678 gfx::Rect view_rect(size_); | |
| 679 gfx::Rect damaged_rect = view_rect.Intersect(rect); | |
| 680 if (damaged_rect.IsEmpty()) | |
| 681 return; | |
| 682 | |
| 683 paint_aggregator_.InvalidateRect(damaged_rect); | |
| 684 | |
| 685 // We may not need to schedule another call to DoDeferredUpdate. | |
| 686 if (update_pending) | |
| 687 return; | |
| 688 if (!paint_aggregator_.HasPendingUpdate()) | |
| 689 return; | |
| 690 if (update_reply_pending()) | |
| 691 return; | |
| 692 | |
| 693 // Perform updating asynchronously. This serves two purposes: | |
| 694 // 1) Ensures that we call WebView::Paint without a bunch of other junk | |
| 695 // on the call stack. | |
| 696 // 2) Allows us to collect more damage rects before painting to help coalesce | |
| 697 // the work that we will need to do. | |
| 698 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( | |
| 699 this, &RenderWidget::CallDoDeferredUpdate)); | |
| 700 } | |
| 701 | |
| 702 void RenderWidget::didScrollRect(int dx, int dy, const WebRect& clip_rect) { | |
| 703 // Drop scrolls on the floor when we are in compositing mode. | |
| 704 // TODO(nduca): stop WebViewImpl from sending scrolls in the first place. | |
| 705 if (is_accelerated_compositing_active_) | |
| 706 return; | |
| 707 | |
| 708 // We only want one pending DoDeferredUpdate call at any time... | |
| 709 bool update_pending = paint_aggregator_.HasPendingUpdate(); | |
| 710 | |
| 711 // The scrolled rect might be outside the bounds of the view. | |
| 712 gfx::Rect view_rect(size_); | |
| 713 gfx::Rect damaged_rect = view_rect.Intersect(clip_rect); | |
| 714 if (damaged_rect.IsEmpty()) | |
| 715 return; | |
| 716 | |
| 717 paint_aggregator_.ScrollRect(dx, dy, damaged_rect); | |
| 718 | |
| 719 // We may not need to schedule another call to DoDeferredUpdate. | |
| 720 if (update_pending) | |
| 721 return; | |
| 722 if (!paint_aggregator_.HasPendingUpdate()) | |
| 723 return; | |
| 724 if (update_reply_pending()) | |
| 725 return; | |
| 726 | |
| 727 // Perform updating asynchronously. This serves two purposes: | |
| 728 // 1) Ensures that we call WebView::Paint without a bunch of other junk | |
| 729 // on the call stack. | |
| 730 // 2) Allows us to collect more damage rects before painting to help coalesce | |
| 731 // the work that we will need to do. | |
| 732 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( | |
| 733 this, &RenderWidget::CallDoDeferredUpdate)); | |
| 734 } | |
| 735 | |
| 736 void RenderWidget::didActivateAcceleratedCompositing(bool active) { | |
| 737 is_accelerated_compositing_active_ = active; | |
| 738 Send(new ViewHostMsg_DidActivateAcceleratedCompositing( | |
| 739 routing_id_, is_accelerated_compositing_active_)); | |
| 740 } | |
| 741 | |
| 742 void RenderWidget::scheduleComposite() { | |
| 743 // TODO(nduca): replace with something a little less hacky. The reason this | |
| 744 // hack is still used is because the Invalidate-DoDeferredUpdate loop | |
| 745 // contains a lot of host-renderer synchronization logic that is still | |
| 746 // important for the accelerated compositing case. The option of simply | |
| 747 // duplicating all that code is less desirable than "faking out" the | |
| 748 // invalidation path using a magical damage rect. | |
| 749 didInvalidateRect(WebRect(0, 0, 1, 1)); | |
| 750 } | |
| 751 | |
| 752 void RenderWidget::scheduleAnimation() { | |
| 753 if (!animation_update_pending_) { | |
| 754 animation_update_pending_ = true; | |
| 755 if (!animation_task_posted_) { | |
| 756 animation_task_posted_ = true; | |
| 757 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( | |
| 758 this, &RenderWidget::AnimationCallback)); | |
| 759 } | |
| 760 } | |
| 761 } | |
| 762 | |
| 763 void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) { | |
| 764 // TODO(darin): Eliminate this temporary. | |
| 765 WebCursor cursor(cursor_info); | |
| 766 | |
| 767 // Only send a SetCursor message if we need to make a change. | |
| 768 if (!current_cursor_.IsEqual(cursor)) { | |
| 769 current_cursor_ = cursor; | |
| 770 Send(new ViewHostMsg_SetCursor(routing_id_, cursor)); | |
| 771 } | |
| 772 } | |
| 773 | |
| 774 // We are supposed to get a single call to Show for a newly created RenderWidget | |
| 775 // that was created via RenderWidget::CreateWebView. So, we wait until this | |
| 776 // point to dispatch the ShowWidget message. | |
| 777 // | |
| 778 // This method provides us with the information about how to display the newly | |
| 779 // created RenderWidget (i.e., as a constrained popup or as a new tab). | |
| 780 // | |
| 781 void RenderWidget::show(WebNavigationPolicy) { | |
| 782 DCHECK(!did_show_) << "received extraneous Show call"; | |
| 783 DCHECK(routing_id_ != MSG_ROUTING_NONE); | |
| 784 DCHECK(opener_id_ != MSG_ROUTING_NONE); | |
| 785 | |
| 786 if (did_show_) | |
| 787 return; | |
| 788 | |
| 789 did_show_ = true; | |
| 790 // NOTE: initial_pos_ may still have its default values at this point, but | |
| 791 // that's okay. It'll be ignored if as_popup is false, or the browser | |
| 792 // process will impose a default position otherwise. | |
| 793 Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_pos_)); | |
| 794 SetPendingWindowRect(initial_pos_); | |
| 795 } | |
| 796 | |
| 797 void RenderWidget::didFocus() { | |
| 798 } | |
| 799 | |
| 800 void RenderWidget::didBlur() { | |
| 801 } | |
| 802 | |
| 803 void RenderWidget::DoDeferredClose() { | |
| 804 Send(new ViewHostMsg_Close(routing_id_)); | |
| 805 } | |
| 806 | |
| 807 void RenderWidget::closeWidgetSoon() { | |
| 808 // If a page calls window.close() twice, we'll end up here twice, but that's | |
| 809 // OK. It is safe to send multiple Close messages. | |
| 810 | |
| 811 // Ask the RenderWidgetHost to initiate close. We could be called from deep | |
| 812 // in Javascript. If we ask the RendwerWidgetHost to close now, the window | |
| 813 // could be closed before the JS finishes executing. So instead, post a | |
| 814 // message back to the message loop, which won't run until the JS is | |
| 815 // complete, and then the Close message can be sent. | |
| 816 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( | |
| 817 this, &RenderWidget::DoDeferredClose)); | |
| 818 } | |
| 819 | |
| 820 void RenderWidget::Close() { | |
| 821 if (webwidget_) { | |
| 822 webwidget_->close(); | |
| 823 webwidget_ = NULL; | |
| 824 } | |
| 825 } | |
| 826 | |
| 827 WebRect RenderWidget::windowRect() { | |
| 828 if (pending_window_rect_count_) | |
| 829 return pending_window_rect_; | |
| 830 | |
| 831 gfx::Rect rect; | |
| 832 Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, &rect)); | |
| 833 return rect; | |
| 834 } | |
| 835 | |
| 836 void RenderWidget::setWindowRect(const WebRect& pos) { | |
| 837 if (did_show_) { | |
| 838 Send(new ViewHostMsg_RequestMove(routing_id_, pos)); | |
| 839 SetPendingWindowRect(pos); | |
| 840 } else { | |
| 841 initial_pos_ = pos; | |
| 842 } | |
| 843 } | |
| 844 | |
| 845 void RenderWidget::SetPendingWindowRect(const WebRect& rect) { | |
| 846 pending_window_rect_ = rect; | |
| 847 pending_window_rect_count_++; | |
| 848 } | |
| 849 | |
| 850 WebRect RenderWidget::rootWindowRect() { | |
| 851 if (pending_window_rect_count_) { | |
| 852 // NOTE(mbelshe): If there is a pending_window_rect_, then getting | |
| 853 // the RootWindowRect is probably going to return wrong results since the | |
| 854 // browser may not have processed the Move yet. There isn't really anything | |
| 855 // good to do in this case, and it shouldn't happen - since this size is | |
| 856 // only really needed for windowToScreen, which is only used for Popups. | |
| 857 return pending_window_rect_; | |
| 858 } | |
| 859 | |
| 860 gfx::Rect rect; | |
| 861 Send(new ViewHostMsg_GetRootWindowRect(routing_id_, host_window_, &rect)); | |
| 862 return rect; | |
| 863 } | |
| 864 | |
| 865 WebRect RenderWidget::windowResizerRect() { | |
| 866 return resizer_rect_; | |
| 867 } | |
| 868 | |
| 869 void RenderWidget::OnSetInputMethodActive(bool is_active) { | |
| 870 // To prevent this renderer process from sending unnecessary IPC messages to | |
| 871 // a browser process, we permit the renderer process to send IPC messages | |
| 872 // only during the input method attached to the browser process is active. | |
| 873 input_method_is_active_ = is_active; | |
| 874 } | |
| 875 | |
| 876 void RenderWidget::OnImeSetComposition( | |
| 877 const string16& text, | |
| 878 const std::vector<WebCompositionUnderline>& underlines, | |
| 879 int selection_start, int selection_end) { | |
| 880 if (!webwidget_) | |
| 881 return; | |
| 882 if (!webwidget_->setComposition( | |
| 883 text, WebVector<WebCompositionUnderline>(underlines), | |
| 884 selection_start, selection_end)) { | |
| 885 // If we failed to set the composition text, then we need to let the browser | |
| 886 // process to cancel the input method's ongoing composition session, to make | |
| 887 // sure we are in a consistent state. | |
| 888 Send(new ViewHostMsg_ImeCancelComposition(routing_id())); | |
| 889 } | |
| 890 } | |
| 891 | |
| 892 void RenderWidget::OnImeConfirmComposition(const string16& text) { | |
| 893 if (webwidget_) | |
| 894 webwidget_->confirmComposition(text); | |
| 895 } | |
| 896 | |
| 897 // This message causes the renderer to render an image of the | |
| 898 // desired_size, regardless of whether the tab is hidden or not. | |
| 899 void RenderWidget::OnMsgPaintAtSize(const TransportDIB::Handle& dib_handle, | |
| 900 int tag, | |
| 901 const gfx::Size& page_size, | |
| 902 const gfx::Size& desired_size) { | |
| 903 if (!webwidget_ || !TransportDIB::is_valid(dib_handle)) { | |
| 904 if (TransportDIB::is_valid(dib_handle)) { | |
| 905 // Close our unused handle. | |
| 906 #if defined(OS_WIN) | |
| 907 ::CloseHandle(dib_handle); | |
| 908 #elif defined(OS_MACOSX) | |
| 909 base::SharedMemory::CloseHandle(dib_handle); | |
| 910 #endif | |
| 911 } | |
| 912 return; | |
| 913 } | |
| 914 | |
| 915 if (page_size.IsEmpty() || desired_size.IsEmpty()) { | |
| 916 // If one of these is empty, then we just return the dib we were | |
| 917 // given, to avoid leaking it. | |
| 918 Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, desired_size)); | |
| 919 return; | |
| 920 } | |
| 921 | |
| 922 // Map the given DIB ID into this process, and unmap it at the end | |
| 923 // of this function. | |
| 924 scoped_ptr<TransportDIB> paint_at_size_buffer( | |
| 925 TransportDIB::CreateWithHandle(dib_handle)); | |
| 926 | |
| 927 gfx::Size canvas_size = page_size; | |
| 928 float x_scale = static_cast<float>(desired_size.width()) / | |
| 929 static_cast<float>(canvas_size.width()); | |
| 930 float y_scale = static_cast<float>(desired_size.height()) / | |
| 931 static_cast<float>(canvas_size.height()); | |
| 932 | |
| 933 gfx::Rect orig_bounds(canvas_size); | |
| 934 canvas_size.set_width(static_cast<int>(canvas_size.width() * x_scale)); | |
| 935 canvas_size.set_height(static_cast<int>(canvas_size.height() * y_scale)); | |
| 936 gfx::Rect bounds(canvas_size); | |
| 937 | |
| 938 scoped_ptr<skia::PlatformCanvas> canvas( | |
| 939 paint_at_size_buffer->GetPlatformCanvas(canvas_size.width(), | |
| 940 canvas_size.height())); | |
| 941 if (!canvas.get()) { | |
| 942 NOTREACHED(); | |
| 943 return; | |
| 944 } | |
| 945 | |
| 946 // Reset bounds to what we actually received, but they should be the | |
| 947 // same. | |
| 948 DCHECK_EQ(bounds.width(), canvas->getDevice()->width()); | |
| 949 DCHECK_EQ(bounds.height(), canvas->getDevice()->height()); | |
| 950 bounds.set_width(canvas->getDevice()->width()); | |
| 951 bounds.set_height(canvas->getDevice()->height()); | |
| 952 | |
| 953 canvas->save(); | |
| 954 // Add the scale factor to the canvas, so that we'll get the desired size. | |
| 955 canvas->scale(SkFloatToScalar(x_scale), SkFloatToScalar(y_scale)); | |
| 956 | |
| 957 // Have to make sure we're laid out at the right size before | |
| 958 // rendering. | |
| 959 gfx::Size old_size = webwidget_->size(); | |
| 960 webwidget_->resize(page_size); | |
| 961 webwidget_->layout(); | |
| 962 | |
| 963 // Paint the entire thing (using original bounds, not scaled bounds). | |
| 964 PaintRect(orig_bounds, orig_bounds.origin(), canvas.get()); | |
| 965 canvas->restore(); | |
| 966 | |
| 967 // Return the widget to its previous size. | |
| 968 webwidget_->resize(old_size); | |
| 969 | |
| 970 Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, bounds.size())); | |
| 971 } | |
| 972 | |
| 973 void RenderWidget::OnMsgRepaint(const gfx::Size& size_to_paint) { | |
| 974 // During shutdown we can just ignore this message. | |
| 975 if (!webwidget_) | |
| 976 return; | |
| 977 | |
| 978 set_next_paint_is_repaint_ack(); | |
| 979 if (is_accelerated_compositing_active_) { | |
| 980 scheduleComposite(); | |
| 981 } else { | |
| 982 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height()); | |
| 983 didInvalidateRect(repaint_rect); | |
| 984 } | |
| 985 } | |
| 986 | |
| 987 void RenderWidget::OnSetTextDirection(WebTextDirection direction) { | |
| 988 if (!webwidget_) | |
| 989 return; | |
| 990 webwidget_->setTextDirection(direction); | |
| 991 } | |
| 992 | |
| 993 webkit::ppapi::PluginInstance* RenderWidget::GetBitmapForOptimizedPluginPaint( | |
| 994 const gfx::Rect& paint_bounds, | |
| 995 TransportDIB** dib, | |
| 996 gfx::Rect* location, | |
| 997 gfx::Rect* clip) { | |
| 998 // Bare RenderWidgets don't support optimized plugin painting. | |
| 999 return NULL; | |
| 1000 } | |
| 1001 | |
| 1002 gfx::Point RenderWidget::GetScrollOffset() { | |
| 1003 // Bare RenderWidgets don't support scroll offset. | |
| 1004 return gfx::Point(0, 0); | |
| 1005 } | |
| 1006 | |
| 1007 void RenderWidget::SetHidden(bool hidden) { | |
| 1008 if (is_hidden_ == hidden) | |
| 1009 return; | |
| 1010 | |
| 1011 // The status has changed. Tell the RenderThread about it. | |
| 1012 is_hidden_ = hidden; | |
| 1013 if (is_hidden_) | |
| 1014 render_thread_->WidgetHidden(); | |
| 1015 else | |
| 1016 render_thread_->WidgetRestored(); | |
| 1017 } | |
| 1018 | |
| 1019 void RenderWidget::SetBackground(const SkBitmap& background) { | |
| 1020 background_ = background; | |
| 1021 | |
| 1022 // Generate a full repaint. | |
| 1023 didInvalidateRect(gfx::Rect(size_.width(), size_.height())); | |
| 1024 } | |
| 1025 | |
| 1026 bool RenderWidget::next_paint_is_resize_ack() const { | |
| 1027 return ViewHostMsg_UpdateRect_Flags::is_resize_ack(next_paint_flags_); | |
| 1028 } | |
| 1029 | |
| 1030 bool RenderWidget::next_paint_is_restore_ack() const { | |
| 1031 return ViewHostMsg_UpdateRect_Flags::is_restore_ack(next_paint_flags_); | |
| 1032 } | |
| 1033 | |
| 1034 void RenderWidget::set_next_paint_is_resize_ack() { | |
| 1035 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK; | |
| 1036 } | |
| 1037 | |
| 1038 void RenderWidget::set_next_paint_is_restore_ack() { | |
| 1039 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK; | |
| 1040 } | |
| 1041 | |
| 1042 void RenderWidget::set_next_paint_is_repaint_ack() { | |
| 1043 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK; | |
| 1044 } | |
| 1045 | |
| 1046 void RenderWidget::UpdateInputMethod() { | |
| 1047 if (!input_method_is_active_) | |
| 1048 return; | |
| 1049 | |
| 1050 WebTextInputType new_type = WebKit::WebTextInputTypeNone; | |
| 1051 WebRect new_caret_bounds; | |
| 1052 | |
| 1053 if (webwidget_) { | |
| 1054 new_type = webwidget_->textInputType(); | |
| 1055 new_caret_bounds = webwidget_->caretOrSelectionBounds(); | |
| 1056 } | |
| 1057 | |
| 1058 // Only sends text input type and caret bounds to the browser process if they | |
| 1059 // are changed. | |
| 1060 if (text_input_type_ != new_type || caret_bounds_ != new_caret_bounds) { | |
| 1061 text_input_type_ = new_type; | |
| 1062 caret_bounds_ = new_caret_bounds; | |
| 1063 Send(new ViewHostMsg_ImeUpdateTextInputState( | |
| 1064 routing_id(), new_type, new_caret_bounds)); | |
| 1065 } | |
| 1066 } | |
| 1067 | |
| 1068 WebScreenInfo RenderWidget::screenInfo() { | |
| 1069 WebScreenInfo results; | |
| 1070 Send(new ViewHostMsg_GetScreenInfo(routing_id_, host_window_, &results)); | |
| 1071 return results; | |
| 1072 } | |
| 1073 | |
| 1074 void RenderWidget::resetInputMethod() { | |
| 1075 if (!input_method_is_active_) | |
| 1076 return; | |
| 1077 | |
| 1078 // If the last text input type is not None, then we should finish any | |
| 1079 // ongoing composition regardless of the new text input type. | |
| 1080 if (text_input_type_ != WebKit::WebTextInputTypeNone) { | |
| 1081 // If a composition text exists, then we need to let the browser process | |
| 1082 // to cancel the input method's ongoing composition session. | |
| 1083 if (webwidget_->confirmComposition()) | |
| 1084 Send(new ViewHostMsg_ImeCancelComposition(routing_id())); | |
| 1085 } | |
| 1086 } | |
| 1087 | |
| 1088 void RenderWidget::SchedulePluginMove( | |
| 1089 const webkit::npapi::WebPluginGeometry& move) { | |
| 1090 size_t i = 0; | |
| 1091 for (; i < plugin_window_moves_.size(); ++i) { | |
| 1092 if (plugin_window_moves_[i].window == move.window) { | |
| 1093 if (move.rects_valid) { | |
| 1094 plugin_window_moves_[i] = move; | |
| 1095 } else { | |
| 1096 plugin_window_moves_[i].visible = move.visible; | |
| 1097 } | |
| 1098 break; | |
| 1099 } | |
| 1100 } | |
| 1101 | |
| 1102 if (i == plugin_window_moves_.size()) | |
| 1103 plugin_window_moves_.push_back(move); | |
| 1104 } | |
| 1105 | |
| 1106 void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) { | |
| 1107 for (WebPluginGeometryVector::iterator i = plugin_window_moves_.begin(); | |
| 1108 i != plugin_window_moves_.end(); ++i) { | |
| 1109 if (i->window == window) { | |
| 1110 plugin_window_moves_.erase(i); | |
| 1111 break; | |
| 1112 } | |
| 1113 } | |
| 1114 } | |
| OLD | NEW |