1 // Copyright (c) 2012 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 "content/plugin/webplugin_proxy.h" 6 7 #include "build/build_config.h" 8 9 #include "base/bind.h" 10 #include "base/lazy_instance.h" 11 #include "base/memory/scoped_handle.h" 12 #include "base/memory/shared_memory.h" 13 #include "build/build_config.h" 14 #include "content/child/npapi/npobject_proxy.h" 15 #include "content/child/npapi/npobject_util.h" 16 #include "content/child/npapi/webplugin_delegate_impl.h" 17 #include "content/child/npapi/webplugin_resource_client.h" 18 #include "content/child/plugin_messages.h" 19 #include "content/plugin/plugin_channel.h" 20 #include "content/plugin/plugin_thread.h" 21 #include "content/public/common/content_client.h" 22 #include "content/public/common/url_constants.h" 23 #include "skia/ext/platform_canvas.h" 24 #include "skia/ext/platform_device.h" 25 #include "third_party/WebKit/public/web/WebBindings.h" 26 #include "ui/gfx/blit.h" 27 #include "ui/gfx/canvas.h" 28 29 #if defined(OS_MACOSX) 30 #include "base/mac/mac_util.h" 31 #include "base/mac/scoped_cftyperef.h" 32 #include "content/plugin/webplugin_accelerated_surface_proxy_mac.h" 33 #endif 34 35 #if defined(USE_X11) 36 #include "ui/base/x/x11_util_internal.h" 37 #endif 38 39 #if defined(OS_WIN) 40 #include "content/common/plugin_process_messages.h" 41 #include "content/public/common/sandbox_init.h" 42 #endif 43 44 using blink::WebBindings; 45 46 namespace content { 47 48 WebPluginProxy::SharedTransportDIB::SharedTransportDIB(TransportDIB* dib) 49 : dib_(dib) { 50 } 51 52 WebPluginProxy::SharedTransportDIB::~SharedTransportDIB() { 53 } 54 55 WebPluginProxy::WebPluginProxy( 56 PluginChannel* channel, 57 int route_id, 58 const GURL& page_url, 59 int host_render_view_routing_id) 60 : channel_(channel), 61 route_id_(route_id), 62 window_npobject_(NULL), 63 plugin_element_(NULL), 64 delegate_(NULL), 65 waiting_for_paint_(false), 66 page_url_(page_url), 67 windowless_buffer_index_(0), 68 host_render_view_routing_id_(host_render_view_routing_id), 69 weak_factory_(this) { 70 #if defined(USE_X11) 71 windowless_shm_pixmaps_[0] = None; 72 windowless_shm_pixmaps_[1] = None; 73 use_shm_pixmap_ = false; 74 75 // If the X server supports SHM pixmaps 76 // and the color depth and masks match, 77 // then consider using SHM pixmaps for windowless plugin painting. 78 XDisplay* display = gfx::GetXDisplay(); 79 if (ui::QuerySharedMemorySupport(display) == ui::SHARED_MEMORY_PIXMAP && 80 gfx::BitsPerPixelForPixmapDepth( 81 display, DefaultDepth(display, DefaultScreen(display))) == 32) { 82 Visual* vis = DefaultVisual(display, DefaultScreen(display)); 83 84 if (vis->red_mask == 0xff0000 && 85 vis->green_mask == 0xff00 && 86 vis->blue_mask == 0xff) 87 use_shm_pixmap_ = true; 88 } 89 #endif 90 } 91 92 WebPluginProxy::~WebPluginProxy() { 93 #if defined(USE_X11) 94 if (windowless_shm_pixmaps_[0] != None) 95 XFreePixmap(gfx::GetXDisplay(), windowless_shm_pixmaps_[0]); 96 if (windowless_shm_pixmaps_[1] != None) 97 XFreePixmap(gfx::GetXDisplay(), windowless_shm_pixmaps_[1]); 98 #endif 99 100 #if defined(OS_MACOSX) 101 // Destroy the surface early, since it may send messages during cleanup. 102 if (accelerated_surface_) 103 accelerated_surface_.reset(); 104 #endif 105 106 if (plugin_element_) 107 WebBindings::releaseObject(plugin_element_); 108 if (window_npobject_) 109 WebBindings::releaseObject(window_npobject_); 110 } 111 112 bool WebPluginProxy::Send(IPC::Message* msg) { 113 return channel_->Send(msg); 114 } 115 116 void WebPluginProxy::SetWindow(gfx::PluginWindowHandle window) { 117 Send(new PluginHostMsg_SetWindow(route_id_, window)); 118 } 119 120 void WebPluginProxy::SetAcceptsInputEvents(bool accepts) { 121 NOTREACHED(); 122 } 123 124 void WebPluginProxy::WillDestroyWindow(gfx::PluginWindowHandle window) { 125 #if defined(OS_WIN) 126 PluginThread::current()->Send( 127 new PluginProcessHostMsg_PluginWindowDestroyed( 128 window, ::GetParent(window))); 129 #elif defined(USE_X11) 130 // Nothing to do. 131 #else 132 NOTIMPLEMENTED(); 133 #endif 134 } 135 136 #if defined(OS_WIN) 137 void WebPluginProxy::SetWindowlessData( 138 HANDLE pump_messages_event, gfx::NativeViewId dummy_activation_window) { 139 HANDLE pump_messages_event_for_renderer = NULL; 140 BrokerDuplicateHandle(pump_messages_event, channel_->peer_pid(), 141 &pump_messages_event_for_renderer, 142 SYNCHRONIZE | EVENT_MODIFY_STATE, 0); 143 DCHECK(pump_messages_event_for_renderer); 144 Send(new PluginHostMsg_SetWindowlessData( 145 route_id_, pump_messages_event_for_renderer, dummy_activation_window)); 146 } 147 #endif 148 149 void WebPluginProxy::CancelResource(unsigned long id) { 150 Send(new PluginHostMsg_CancelResource(route_id_, id)); 151 resource_clients_.erase(id); 152 } 153 154 void WebPluginProxy::Invalidate() { 155 gfx::Rect rect(0, 0, 156 delegate_->GetRect().width(), 157 delegate_->GetRect().height()); 158 InvalidateRect(rect); 159 } 160 161 void WebPluginProxy::InvalidateRect(const gfx::Rect& rect) { 162 #if defined(OS_MACOSX) 163 // If this is a Core Animation plugin, all we need to do is inform the 164 // delegate. 165 if (!windowless_context()) { 166 delegate_->PluginDidInvalidate(); 167 return; 168 } 169 170 // Some plugins will send invalidates larger than their own rect when 171 // offscreen, so constrain invalidates to the plugin rect. 172 gfx::Rect plugin_rect = delegate_->GetRect(); 173 plugin_rect.set_origin(gfx::Point(0, 0)); 174 plugin_rect.Intersect(rect); 175 const gfx::Rect invalidate_rect(plugin_rect); 176 #else 177 const gfx::Rect invalidate_rect(rect); 178 #endif 179 damaged_rect_.Union(invalidate_rect); 180 // Ignore NPN_InvalidateRect calls with empty rects. Also don't send an 181 // invalidate if it's outside the clipping region, since if we did it won't 182 // lead to a paint and we'll be stuck waiting forever for a DidPaint response. 183 // 184 // TODO(piman): There is a race condition here, because this test assumes 185 // that when the paint actually occurs, the clip rect will not have changed. 186 // This is not true because scrolling (or window resize) could occur and be 187 // handled by the renderer before it receives the InvalidateRect message, 188 // changing the clip rect and then not painting. 189 if (damaged_rect_.IsEmpty() || 190 !delegate_->GetClipRect().Intersects(damaged_rect_)) 191 return; 192 193 // Only send a single InvalidateRect message at a time. From DidPaint we 194 // will dispatch an additional InvalidateRect message if necessary. 195 if (!waiting_for_paint_) { 196 waiting_for_paint_ = true; 197 // Invalidates caused by calls to NPN_InvalidateRect/NPN_InvalidateRgn 198 // need to be painted asynchronously as per the NPAPI spec. 199 base::MessageLoop::current()->PostTask( 200 FROM_HERE, 201 base::Bind(&WebPluginProxy::OnPaint, 202 weak_factory_.GetWeakPtr(), 203 damaged_rect_)); 204 damaged_rect_ = gfx::Rect(); 205 } 206 } 207 208 NPObject* WebPluginProxy::GetWindowScriptNPObject() { 209 if (window_npobject_) 210 return window_npobject_; 211 212 int npobject_route_id = channel_->GenerateRouteID(); 213 bool success = false; 214 Send(new PluginHostMsg_GetWindowScriptNPObject( 215 route_id_, npobject_route_id, &success)); 216 if (!success) 217 return NULL; 218 219 // PluginChannel creates a dummy owner identifier for unknown owners, so 220 // use that. 221 NPP owner = channel_->GetExistingNPObjectOwner(MSG_ROUTING_NONE); 222 223 window_npobject_ = NPObjectProxy::Create(channel_.get(), 224 npobject_route_id, 225 host_render_view_routing_id_, 226 page_url_, 227 owner); 228 229 return window_npobject_; 230 } 231 232 NPObject* WebPluginProxy::GetPluginElement() { 233 if (plugin_element_) 234 return plugin_element_; 235 236 int npobject_route_id = channel_->GenerateRouteID(); 237 bool success = false; 238 Send(new PluginHostMsg_GetPluginElement(route_id_, npobject_route_id, 239 &success)); 240 if (!success) 241 return NULL; 242 243 // PluginChannel creates a dummy owner identifier for unknown owners, so 244 // use that. 245 NPP owner = channel_->GetExistingNPObjectOwner(MSG_ROUTING_NONE); 246 247 plugin_element_ = NPObjectProxy::Create(channel_.get(), 248 npobject_route_id, 249 host_render_view_routing_id_, 250 page_url_, 251 owner); 252 253 return plugin_element_; 254 } 255 256 bool WebPluginProxy::FindProxyForUrl(const GURL& url, std::string* proxy_list) { 257 bool result = false; 258 Send(new PluginHostMsg_ResolveProxy(route_id_, url, &result, proxy_list)); 259 return result; 260 } 261 262 void WebPluginProxy::SetCookie(const GURL& url, 263 const GURL& first_party_for_cookies, 264 const std::string& cookie) { 265 Send(new PluginHostMsg_SetCookie(route_id_, url, 266 first_party_for_cookies, cookie)); 267 } 268 269 std::string WebPluginProxy::GetCookies(const GURL& url, 270 const GURL& first_party_for_cookies) { 271 std::string cookies; 272 Send(new PluginHostMsg_GetCookies(route_id_, url, 273 first_party_for_cookies, &cookies)); 274 275 return cookies; 276 } 277 278 WebPluginResourceClient* WebPluginProxy::GetResourceClient(int id) { 279 ResourceClientMap::iterator iterator = resource_clients_.find(id); 280 // The IPC messages which deal with streams are now asynchronous. It is 281 // now possible to receive stream messages from the renderer for streams 282 // which may have been cancelled by the plugin. 283 if (iterator == resource_clients_.end()) { 284 return NULL; 285 } 286 287 return iterator->second; 288 } 289 290 int WebPluginProxy::GetRendererId() { 291 if (channel_.get()) 292 return channel_->renderer_id(); 293 return -1; 294 } 295 296 void WebPluginProxy::DidPaint() { 297 // If we have an accumulated damaged rect, then check to see if we need to 298 // send out another InvalidateRect message. 299 waiting_for_paint_ = false; 300 if (!damaged_rect_.IsEmpty()) 301 InvalidateRect(damaged_rect_); 302 } 303 304 void WebPluginProxy::OnResourceCreated(int resource_id, 305 WebPluginResourceClient* client) { 306 DCHECK(resource_clients_.find(resource_id) == resource_clients_.end()); 307 resource_clients_[resource_id] = client; 308 } 309 310 void WebPluginProxy::HandleURLRequest(const char* url, 311 const char* method, 312 const char* target, 313 const char* buf, 314 unsigned int len, 315 int notify_id, 316 bool popups_allowed, 317 bool notify_redirects) { 318 if (!target && (0 == base::strcasecmp(method, "GET"))) { 319 // Please refer to https://bugzilla.mozilla.org/show_bug.cgi?id=366082 320 // for more details on this. 321 if (delegate_->GetQuirks() & 322 WebPluginDelegateImpl::PLUGIN_QUIRK_BLOCK_NONSTANDARD_GETURL_REQUESTS) { 323 GURL request_url(url); 324 if (!request_url.SchemeIs(kHttpScheme) && 325 !request_url.SchemeIs(kHttpsScheme) && 326 !request_url.SchemeIs(kFtpScheme)) { 327 return; 328 } 329 } 330 } 331 332 PluginHostMsg_URLRequest_Params params; 333 params.url = url; 334 params.method = method; 335 if (target) 336 params.target = std::string(target); 337 338 if (len) { 339 params.buffer.resize(len); 340 memcpy(¶ms.buffer.front(), buf, len); 341 } 342 343 params.notify_id = notify_id; 344 params.popups_allowed = popups_allowed; 345 params.notify_redirects = notify_redirects; 346 347 Send(new PluginHostMsg_URLRequest(route_id_, params)); 348 } 349 350 void WebPluginProxy::Paint(const gfx::Rect& rect) { 351 #if defined(OS_MACOSX) 352 if (!windowless_context()) 353 return; 354 #else 355 if (!windowless_canvas() || !windowless_canvas()->getDevice()) 356 return; 357 #endif 358 359 // Clear the damaged area so that if the plugin doesn't paint there we won't 360 // end up with the old values. 361 gfx::Rect offset_rect = rect; 362 offset_rect.Offset(delegate_->GetRect().OffsetFromOrigin()); 363 #if defined(OS_MACOSX) 364 CGContextSaveGState(windowless_context()); 365 // It is possible for windowless_contexts_ to change during plugin painting 366 // (since the plugin can make a synchronous call during paint event handling), 367 // in which case we don't want to try to restore later. Not an owning ref 368 // since owning the ref without owning the shared backing memory doesn't make 369 // sense, so this should only be used for pointer comparisons. 370 CGContextRef saved_context_weak = windowless_context(); 371 // We also save the buffer index for the comparison because if we flip buffers 372 // but haven't reallocated them then we do need to restore the context because 373 // it is going to continue to be used. 374 int saved_index = windowless_buffer_index_; 375 376 CGContextClipToRect(windowless_context(), rect.ToCGRect()); 377 // TODO(caryclark): This is a temporary workaround to allow the Darwin / Skia 378 // port to share code with the Darwin / CG port. All ports will eventually use 379 // the common code below. 380 delegate_->CGPaint(windowless_context(), rect); 381 if (windowless_contexts_[saved_index].get() == saved_context_weak) 382 CGContextRestoreGState(windowless_contexts_[saved_index]); 383 #else 384 // See above comment about windowless_context_ changing. 385 // http::/crbug.com/139462 386 skia::RefPtr<skia::PlatformCanvas> saved_canvas = windowless_canvas(); 387 #if defined(USE_X11) 388 scoped_refptr<SharedTransportDIB> local_dib_ref( 389 windowless_dibs_[windowless_buffer_index_]); 390 #endif 391 392 saved_canvas->save(); 393 394 // The given clip rect is relative to the plugin coordinate system. 395 SkRect sk_rect = { SkIntToScalar(rect.x()), 396 SkIntToScalar(rect.y()), 397 SkIntToScalar(rect.right()), 398 SkIntToScalar(rect.bottom()) }; 399 saved_canvas->clipRect(sk_rect); 400 401 // Fill a transparent value so that if the plugin supports transparency that 402 // will work. 403 saved_canvas->drawColor(SkColorSetARGB(0, 0, 0, 0), SkXfermode::kSrc_Mode); 404 405 // Bring the windowless canvas into the window coordinate system, which is 406 // how the plugin expects to draw (since the windowless API was originally 407 // designed just for scribbling over the web page). 408 saved_canvas->translate(SkIntToScalar(-delegate_->GetRect().x()), 409 SkIntToScalar(-delegate_->GetRect().y())); 410 411 // Before we send the invalidate, paint so that renderer uses the updated 412 // bitmap. 413 delegate_->Paint(saved_canvas.get(), offset_rect); 414 415 saved_canvas->restore(); 416 #endif 417 } 418 419 void WebPluginProxy::UpdateGeometry( 420 const gfx::Rect& window_rect, 421 const gfx::Rect& clip_rect, 422 const TransportDIB::Handle& windowless_buffer0, 423 const TransportDIB::Handle& windowless_buffer1, 424 int windowless_buffer_index) { 425 gfx::Rect old = delegate_->GetRect(); 426 gfx::Rect old_clip_rect = delegate_->GetClipRect(); 427 428 // Update the buffers before doing anything that could call into plugin code, 429 // so that we don't process buffer changes out of order if plugins make 430 // synchronous calls that lead to nested UpdateGeometry calls. 431 if (TransportDIB::is_valid_handle(windowless_buffer0)) { 432 // The plugin's rect changed, so now we have new buffers to draw into. 433 SetWindowlessBuffers(windowless_buffer0, 434 windowless_buffer1, 435 window_rect); 436 } 437 438 DCHECK(0 <= windowless_buffer_index && windowless_buffer_index <= 1); 439 windowless_buffer_index_ = windowless_buffer_index; 440 #if defined(USE_X11) 441 delegate_->SetWindowlessShmPixmap(windowless_shm_pixmap()); 442 #endif 443 444 #if defined(OS_MACOSX) 445 delegate_->UpdateGeometryAndContext( 446 window_rect, clip_rect, windowless_context()); 447 #else 448 delegate_->UpdateGeometry(window_rect, clip_rect); 449 #endif 450 451 // Send over any pending invalidates which occured when the plugin was 452 // off screen. 453 if (delegate_->IsWindowless() && !clip_rect.IsEmpty() && 454 !damaged_rect_.IsEmpty()) { 455 InvalidateRect(damaged_rect_); 456 } 457 } 458 459 #if defined(OS_WIN) 460 461 void WebPluginProxy::CreateCanvasFromHandle( 462 const TransportDIB::Handle& dib_handle, 463 const gfx::Rect& window_rect, 464 skia::RefPtr<skia::PlatformCanvas>* canvas) { 465 *canvas = skia::AdoptRef( 466 skia::CreatePlatformCanvas(window_rect.width(), 467 window_rect.height(), 468 true, 469 dib_handle, 470 skia::RETURN_NULL_ON_FAILURE)); 471 // The canvas does not own the section so we need to close it now. 472 CloseHandle(dib_handle); 473 } 474 475 void WebPluginProxy::SetWindowlessBuffers( 476 const TransportDIB::Handle& windowless_buffer0, 477 const TransportDIB::Handle& windowless_buffer1, 478 const gfx::Rect& window_rect) { 479 CreateCanvasFromHandle(windowless_buffer0, 480 window_rect, 481 &windowless_canvases_[0]); 482 if (!windowless_canvases_[0]) { 483 windowless_canvases_[1].clear(); 484 return; 485 } 486 CreateCanvasFromHandle(windowless_buffer1, 487 window_rect, 488 &windowless_canvases_[1]); 489 if (!windowless_canvases_[1]) { 490 windowless_canvases_[0].clear(); 491 return; 492 } 493 } 494 495 #elif defined(OS_MACOSX) 496 497 void WebPluginProxy::CreateDIBAndCGContextFromHandle( 498 const TransportDIB::Handle& dib_handle, 499 const gfx::Rect& window_rect, 500 scoped_ptr<TransportDIB>* dib_out, 501 base::ScopedCFTypeRef<CGContextRef>* cg_context_out) { 502 // Convert the shared memory handle to a handle that works in our process, 503 // and then use that to create a CGContextRef. 504 TransportDIB* dib = TransportDIB::Map(dib_handle); 505 CGContextRef cg_context = NULL; 506 if (dib) { 507 cg_context = CGBitmapContextCreate( 508 dib->memory(), 509 window_rect.width(), 510 window_rect.height(), 511 8, 512 4 * window_rect.width(), 513 base::mac::GetSystemColorSpace(), 514 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); 515 CGContextTranslateCTM(cg_context, 0, window_rect.height()); 516 CGContextScaleCTM(cg_context, 1, -1); 517 } 518 dib_out->reset(dib); 519 cg_context_out->reset(cg_context); 520 } 521 522 void WebPluginProxy::SetWindowlessBuffers( 523 const TransportDIB::Handle& windowless_buffer0, 524 const TransportDIB::Handle& windowless_buffer1, 525 const gfx::Rect& window_rect) { 526 CreateDIBAndCGContextFromHandle(windowless_buffer0, 527 window_rect, 528 &windowless_dibs_[0], 529 &windowless_contexts_[0]); 530 CreateDIBAndCGContextFromHandle(windowless_buffer1, 531 window_rect, 532 &windowless_dibs_[1], 533 &windowless_contexts_[1]); 534 } 535 536 #elif defined(TOOLKIT_GTK) 537 538 void WebPluginProxy::CreateDIBAndCanvasFromHandle( 539 const TransportDIB::Handle& dib_handle, 540 const gfx::Rect& window_rect, 541 scoped_refptr<SharedTransportDIB>* dib_out, 542 skia::RefPtr<skia::PlatformCanvas>* canvas) { 543 TransportDIB* dib = TransportDIB::Map(dib_handle); 544 // dib may be NULL if the renderer has already destroyed the TransportDIB by 545 // the time we receive the handle, e.g. in case of multiple resizes. 546 if (dib) { 547 *canvas = skia::AdoptRef( 548 dib->GetPlatformCanvas(window_rect.width(), window_rect.height())); 549 } else { 550 canvas->clear(); 551 } 552 *dib_out = new SharedTransportDIB(dib); 553 } 554 555 void WebPluginProxy::CreateShmPixmapFromDIB( 556 TransportDIB* dib, 557 const gfx::Rect& window_rect, 558 XID* pixmap_out) { 559 if (dib) { 560 XDisplay* display = gfx::GetXDisplay(); 561 XID root_window = ui::GetX11RootWindow(); 562 XShmSegmentInfo shminfo = {0}; 563 564 if (*pixmap_out != None) 565 XFreePixmap(display, *pixmap_out); 566 567 shminfo.shmseg = dib->MapToX(display); 568 // Create a shared memory pixmap based on the image buffer. 569 *pixmap_out = XShmCreatePixmap(display, root_window, 570 NULL, &shminfo, 571 window_rect.width(), window_rect.height(), 572 DefaultDepth(display, 573 DefaultScreen(display))); 574 } 575 } 576 577 void WebPluginProxy::SetWindowlessBuffers( 578 const TransportDIB::Handle& windowless_buffer0, 579 const TransportDIB::Handle& windowless_buffer1, 580 const gfx::Rect& window_rect) { 581 CreateDIBAndCanvasFromHandle(windowless_buffer0, 582 window_rect, 583 &windowless_dibs_[0], 584 &windowless_canvases_[0]); 585 CreateDIBAndCanvasFromHandle(windowless_buffer1, 586 window_rect, 587 &windowless_dibs_[1], 588 &windowless_canvases_[1]); 589 590 // If SHM pixmaps support is available, create SHM pixmaps to pass to the 591 // delegate for windowless plugin painting. 592 if (delegate_->IsWindowless() && use_shm_pixmap_) { 593 CreateShmPixmapFromDIB(windowless_dibs_[0]->dib(), 594 window_rect, 595 &windowless_shm_pixmaps_[0]); 596 CreateShmPixmapFromDIB(windowless_dibs_[1]->dib(), 597 window_rect, 598 &windowless_shm_pixmaps_[1]); 599 } 600 } 601 602 #else 603 604 void WebPluginProxy::SetWindowlessBuffers( 605 const TransportDIB::Handle& windowless_buffer0, 606 const TransportDIB::Handle& windowless_buffer1, 607 const gfx::Rect& window_rect) { 608 NOTIMPLEMENTED(); 609 } 610 611 #endif 612 613 void WebPluginProxy::CancelDocumentLoad() { 614 Send(new PluginHostMsg_CancelDocumentLoad(route_id_)); 615 } 616 617 void WebPluginProxy::InitiateHTTPRangeRequest( 618 const char* url, const char* range_info, int range_request_id) { 619 Send(new PluginHostMsg_InitiateHTTPRangeRequest( 620 route_id_, url, range_info, range_request_id)); 621 } 622 623 void WebPluginProxy::DidStartLoading() { 624 Send(new PluginHostMsg_DidStartLoading(route_id_)); 625 } 626 627 void WebPluginProxy::DidStopLoading() { 628 Send(new PluginHostMsg_DidStopLoading(route_id_)); 629 } 630 631 void WebPluginProxy::SetDeferResourceLoading(unsigned long resource_id, 632 bool defer) { 633 Send(new PluginHostMsg_DeferResourceLoading(route_id_, resource_id, defer)); 634 } 635 636 #if defined(OS_MACOSX) 637 void WebPluginProxy::FocusChanged(bool focused) { 638 IPC::Message* msg = new PluginHostMsg_FocusChanged(route_id_, focused); 639 Send(msg); 640 } 641 642 void WebPluginProxy::StartIme() { 643 IPC::Message* msg = new PluginHostMsg_StartIme(route_id_); 644 // This message can be sent during event-handling, and needs to be delivered 645 // within that context. 646 msg->set_unblock(true); 647 Send(msg); 648 } 649 650 WebPluginAcceleratedSurface* WebPluginProxy::GetAcceleratedSurface( 651 gfx::GpuPreference gpu_preference) { 652 if (!accelerated_surface_) 653 accelerated_surface_.reset( 654 WebPluginAcceleratedSurfaceProxy::Create(this, gpu_preference)); 655 return accelerated_surface_.get(); 656 } 657 658 void WebPluginProxy::AcceleratedPluginEnabledRendering() { 659 Send(new PluginHostMsg_AcceleratedPluginEnabledRendering(route_id_)); 660 } 661 662 void WebPluginProxy::AcceleratedPluginAllocatedIOSurface(int32 width, 663 int32 height, 664 uint32 surface_id) { 665 Send(new PluginHostMsg_AcceleratedPluginAllocatedIOSurface( 666 route_id_, width, height, surface_id)); 667 } 668 669 void WebPluginProxy::AcceleratedPluginSwappedIOSurface() { 670 Send(new PluginHostMsg_AcceleratedPluginSwappedIOSurface( 671 route_id_)); 672 } 673 #endif 674 675 void WebPluginProxy::OnPaint(const gfx::Rect& damaged_rect) { 676 GetContentClient()->SetActiveURL(page_url_); 677 678 Paint(damaged_rect); 679 Send(new PluginHostMsg_InvalidateRect(route_id_, damaged_rect)); 680 } 681 682 bool WebPluginProxy::IsOffTheRecord() { 683 return channel_->incognito(); 684 } 685 686 void WebPluginProxy::ResourceClientDeleted( 687 WebPluginResourceClient* resource_client) { 688 // resource_client->ResourceId() is 0 at this point, so can't use it as an 689 // index into the map. 690 ResourceClientMap::iterator index = resource_clients_.begin(); 691 while (index != resource_clients_.end()) { 692 WebPluginResourceClient* client = (*index).second; 693 if (client == resource_client) { 694 resource_clients_.erase(index); 695 return; 696 } else { 697 index++; 698 } 699 } 700 } 701 702 void WebPluginProxy::URLRedirectResponse(bool allow, int resource_id) { 703 Send(new PluginHostMsg_URLRedirectResponse(route_id_, allow, resource_id)); 704 } 705 706 bool WebPluginProxy::CheckIfRunInsecureContent(const GURL& url) { 707 bool result = true; 708 Send(new PluginHostMsg_CheckIfRunInsecureContent( 709 host_render_view_routing_id_, url, &result)); 710 return result; 711 } 712 713 #if defined(OS_WIN) && !defined(USE_AURA) 714 void WebPluginProxy::UpdateIMEStatus() { 715 // Retrieve the IME status from a plug-in and send it to a renderer process 716 // when the plug-in has updated it. 717 int input_type; 718 gfx::Rect caret_rect; 719 if (!delegate_->GetIMEStatus(&input_type, &caret_rect)) 720 return; 721 722 Send(new PluginHostMsg_NotifyIMEStatus(route_id_, input_type, caret_rect)); 723 } 724 #endif 725 726 } // namespace content 727