Home | History | Annotate | Download | only in npapi
      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/renderer/npapi/webplugin_delegate_proxy.h"
      6 
      7 #if defined(TOOLKIT_GTK)
      8 #include <gtk/gtk.h>
      9 #elif defined(USE_X11)
     10 #include <cairo/cairo.h>
     11 #endif
     12 
     13 #include <algorithm>
     14 
     15 #include "base/auto_reset.h"
     16 #include "base/basictypes.h"
     17 #include "base/command_line.h"
     18 #include "base/file_util.h"
     19 #include "base/logging.h"
     20 #include "base/memory/ref_counted.h"
     21 #include "base/memory/scoped_ptr.h"
     22 #include "base/process/process.h"
     23 #include "base/strings/string_split.h"
     24 #include "base/strings/string_util.h"
     25 #include "base/strings/utf_string_conversions.h"
     26 #include "base/version.h"
     27 #include "content/child/child_process.h"
     28 #include "content/child/npapi/npobject_proxy.h"
     29 #include "content/child/npapi/npobject_stub.h"
     30 #include "content/child/npapi/npobject_util.h"
     31 #include "content/child/npapi/webplugin.h"
     32 #include "content/child/plugin_messages.h"
     33 #include "content/common/content_constants_internal.h"
     34 #include "content/common/view_messages.h"
     35 #include "content/public/renderer/content_renderer_client.h"
     36 #include "content/renderer/npapi/plugin_channel_host.h"
     37 #include "content/renderer/render_thread_impl.h"
     38 #include "content/renderer/render_view_impl.h"
     39 #include "content/renderer/sad_plugin.h"
     40 #include "ipc/ipc_channel_handle.h"
     41 #include "net/base/mime_util.h"
     42 #include "skia/ext/platform_canvas.h"
     43 #include "third_party/WebKit/public/web/WebBindings.h"
     44 #include "third_party/WebKit/public/web/WebDocument.h"
     45 #include "third_party/WebKit/public/web/WebFrame.h"
     46 #include "third_party/WebKit/public/web/WebView.h"
     47 #include "third_party/WebKit/public/platform/WebDragData.h"
     48 #include "third_party/WebKit/public/platform/WebString.h"
     49 #include "ui/gfx/blit.h"
     50 #include "ui/gfx/canvas.h"
     51 #include "ui/gfx/native_widget_types.h"
     52 #include "ui/gfx/size.h"
     53 #include "ui/gfx/skia_util.h"
     54 #include "webkit/common/cursors/webcursor.h"
     55 #include "webkit/glue/webkit_glue.h"
     56 
     57 #if defined(OS_POSIX)
     58 #include "ipc/ipc_channel_posix.h"
     59 #endif
     60 
     61 #if defined(OS_MACOSX)
     62 #include "base/mac/mac_util.h"
     63 #endif
     64 
     65 #if defined(OS_WIN)
     66 #include "content/public/common/sandbox_init.h"
     67 #endif
     68 
     69 using WebKit::WebBindings;
     70 using WebKit::WebCursorInfo;
     71 using WebKit::WebDragData;
     72 using WebKit::WebInputEvent;
     73 using WebKit::WebString;
     74 using WebKit::WebView;
     75 
     76 namespace content {
     77 
     78 namespace {
     79 
     80 class ScopedLogLevel {
     81  public:
     82   explicit ScopedLogLevel(int level);
     83   ~ScopedLogLevel();
     84 
     85  private:
     86   int old_level_;
     87 
     88   DISALLOW_COPY_AND_ASSIGN(ScopedLogLevel);
     89 };
     90 
     91 ScopedLogLevel::ScopedLogLevel(int level)
     92     : old_level_(logging::GetMinLogLevel()) {
     93   logging::SetMinLogLevel(level);
     94 }
     95 
     96 ScopedLogLevel::~ScopedLogLevel() {
     97   logging::SetMinLogLevel(old_level_);
     98 }
     99 
    100 // Proxy for WebPluginResourceClient.  The object owns itself after creation,
    101 // deleting itself after its callback has been called.
    102 class ResourceClientProxy : public WebPluginResourceClient {
    103  public:
    104   ResourceClientProxy(PluginChannelHost* channel, int instance_id)
    105     : channel_(channel), instance_id_(instance_id), resource_id_(0),
    106       multibyte_response_expected_(false) {
    107   }
    108 
    109   virtual ~ResourceClientProxy() {
    110   }
    111 
    112   void Initialize(unsigned long resource_id, const GURL& url, int notify_id) {
    113     resource_id_ = resource_id;
    114     channel_->Send(new PluginMsg_HandleURLRequestReply(
    115         instance_id_, resource_id, url, notify_id));
    116   }
    117 
    118   void InitializeForSeekableStream(unsigned long resource_id,
    119                                    int range_request_id) {
    120     resource_id_ = resource_id;
    121     multibyte_response_expected_ = true;
    122     channel_->Send(new PluginMsg_HTTPRangeRequestReply(
    123         instance_id_, resource_id, range_request_id));
    124   }
    125 
    126   // PluginResourceClient implementation:
    127   virtual void WillSendRequest(const GURL& url, int http_status_code) OVERRIDE {
    128     DCHECK(channel_.get() != NULL);
    129     channel_->Send(new PluginMsg_WillSendRequest(
    130         instance_id_, resource_id_, url, http_status_code));
    131   }
    132 
    133   virtual void DidReceiveResponse(const std::string& mime_type,
    134                                   const std::string& headers,
    135                                   uint32 expected_length,
    136                                   uint32 last_modified,
    137                                   bool request_is_seekable) OVERRIDE {
    138     DCHECK(channel_.get() != NULL);
    139     PluginMsg_DidReceiveResponseParams params;
    140     params.id = resource_id_;
    141     params.mime_type = mime_type;
    142     params.headers = headers;
    143     params.expected_length = expected_length;
    144     params.last_modified = last_modified;
    145     params.request_is_seekable = request_is_seekable;
    146     // Grab a reference on the underlying channel so it does not get
    147     // deleted from under us.
    148     scoped_refptr<PluginChannelHost> channel_ref(channel_);
    149     channel_->Send(new PluginMsg_DidReceiveResponse(instance_id_, params));
    150   }
    151 
    152   virtual void DidReceiveData(const char* buffer,
    153                               int length,
    154                               int data_offset) OVERRIDE {
    155     DCHECK(channel_.get() != NULL);
    156     DCHECK_GT(length, 0);
    157     std::vector<char> data;
    158     data.resize(static_cast<size_t>(length));
    159     memcpy(&data.front(), buffer, length);
    160     // Grab a reference on the underlying channel so it does not get
    161     // deleted from under us.
    162     scoped_refptr<PluginChannelHost> channel_ref(channel_);
    163     channel_->Send(new PluginMsg_DidReceiveData(instance_id_, resource_id_,
    164                                                 data, data_offset));
    165   }
    166 
    167   virtual void DidFinishLoading(unsigned long resource_id) OVERRIDE {
    168     DCHECK(channel_.get() != NULL);
    169     DCHECK_EQ(resource_id, resource_id_);
    170     channel_->Send(new PluginMsg_DidFinishLoading(instance_id_, resource_id_));
    171     channel_ = NULL;
    172     base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    173   }
    174 
    175   virtual void DidFail(unsigned long resource_id) OVERRIDE {
    176     DCHECK(channel_.get() != NULL);
    177     DCHECK_EQ(resource_id, resource_id_);
    178     channel_->Send(new PluginMsg_DidFail(instance_id_, resource_id_));
    179     channel_ = NULL;
    180     base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    181   }
    182 
    183   virtual bool IsMultiByteResponseExpected() OVERRIDE {
    184     return multibyte_response_expected_;
    185   }
    186 
    187   virtual int ResourceId() OVERRIDE {
    188     return resource_id_;
    189   }
    190 
    191  private:
    192   scoped_refptr<PluginChannelHost> channel_;
    193   int instance_id_;
    194   unsigned long resource_id_;
    195   // Set to true if the response expected is a multibyte response.
    196   // For e.g. response for a HTTP byte range request.
    197   bool multibyte_response_expected_;
    198 };
    199 
    200 }  // namespace
    201 
    202 WebPluginDelegateProxy::WebPluginDelegateProxy(
    203     const std::string& mime_type,
    204     const base::WeakPtr<RenderViewImpl>& render_view)
    205     : render_view_(render_view),
    206       plugin_(NULL),
    207       uses_shared_bitmaps_(false),
    208 #if defined(OS_MACOSX)
    209       uses_compositor_(false),
    210 #elif defined(OS_WIN)
    211       dummy_activation_window_(NULL),
    212 #endif
    213       window_(gfx::kNullPluginWindow),
    214       mime_type_(mime_type),
    215       instance_id_(MSG_ROUTING_NONE),
    216       npobject_(NULL),
    217       npp_(new NPP_t),
    218       sad_plugin_(NULL),
    219       invalidate_pending_(false),
    220       transparent_(false),
    221       front_buffer_index_(0),
    222       page_url_(render_view_->webview()->mainFrame()->document().url()) {
    223 }
    224 
    225 WebPluginDelegateProxy::~WebPluginDelegateProxy() {
    226   if (npobject_)
    227     WebBindings::releaseObject(npobject_);
    228 }
    229 
    230 WebPluginDelegateProxy::SharedBitmap::SharedBitmap() {}
    231 
    232 WebPluginDelegateProxy::SharedBitmap::~SharedBitmap() {}
    233 
    234 void WebPluginDelegateProxy::PluginDestroyed() {
    235 #if defined(OS_MACOSX) || defined(OS_WIN)
    236   // Ensure that the renderer doesn't think the plugin still has focus.
    237   if (render_view_)
    238     render_view_->PluginFocusChanged(false, instance_id_);
    239 #endif
    240 
    241 #if defined(OS_WIN)
    242   if (dummy_activation_window_ && render_view_) {
    243     render_view_->Send(new ViewHostMsg_WindowlessPluginDummyWindowDestroyed(
    244         render_view_->routing_id(), dummy_activation_window_));
    245   }
    246   dummy_activation_window_ = NULL;
    247 #endif
    248 
    249   if (window_)
    250     WillDestroyWindow();
    251 
    252   if (render_view_.get())
    253     render_view_->UnregisterPluginDelegate(this);
    254 
    255   if (channel_host_.get()) {
    256     Send(new PluginMsg_DestroyInstance(instance_id_));
    257 
    258     // Must remove the route after sending the destroy message, rather than
    259     // before, since RemoveRoute can lead to all the outstanding NPObjects
    260     // being told the channel went away if this was the last instance.
    261     channel_host_->RemoveRoute(instance_id_);
    262 
    263     // Remove the mapping between our instance-Id and NPP identifiers, used by
    264     // the channel to track object ownership, before releasing it.
    265     channel_host_->RemoveMappingForNPObjectOwner(instance_id_);
    266 
    267     // Release the channel host now. If we are is the last reference to the
    268     // channel, this avoids a race where this renderer asks a new connection to
    269     // the same plugin between now and the time 'this' is actually deleted.
    270     // Destroying the channel host is what releases the channel name -> FD
    271     // association on POSIX, and if we ask for a new connection before it is
    272     // released, the plugin will give us a new FD, and we'll assert when trying
    273     // to associate it with the channel name.
    274     channel_host_ = NULL;
    275   }
    276 
    277   plugin_ = NULL;
    278 
    279   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    280 }
    281 
    282 bool WebPluginDelegateProxy::Initialize(
    283     const GURL& url,
    284     const std::vector<std::string>& arg_names,
    285     const std::vector<std::string>& arg_values,
    286     WebPlugin* plugin,
    287     bool load_manually) {
    288   // TODO(shess): Attempt to work around http://crbug.com/97285 and
    289   // http://crbug.com/141055 by retrying the connection.  Reports seem
    290   // to indicate that the plugin hasn't crashed, and that the problem
    291   // is not 100% persistent.
    292   const size_t kAttempts = 2;
    293 
    294   bool result = false;
    295   scoped_refptr<PluginChannelHost> channel_host;
    296   int instance_id = 0;
    297 
    298   for (size_t attempt = 0; !result && attempt < kAttempts; attempt++) {
    299 #if defined(OS_MACOSX)
    300     // TODO(shess): Debugging for http://crbug.com/97285 .  See comment
    301     // in plugin_channel_host.cc.
    302     scoped_ptr<base::AutoReset<bool> > track_nested_removes(
    303         new base::AutoReset<bool>(PluginChannelHost::GetRemoveTrackingFlag(),
    304                                   true));
    305 #endif
    306 
    307     IPC::ChannelHandle channel_handle;
    308     if (!RenderThreadImpl::current()->Send(new ViewHostMsg_OpenChannelToPlugin(
    309             render_view_->routing_id(), url, page_url_, mime_type_,
    310             &channel_handle, &info_))) {
    311       continue;
    312     }
    313 
    314     if (channel_handle.name.empty()) {
    315       // We got an invalid handle.  Either the plugin couldn't be found (which
    316       // shouldn't happen, since if we got here the plugin should exist) or the
    317       // plugin crashed on initialization.
    318       if (!info_.path.empty()) {
    319         render_view_->PluginCrashed(info_.path, base::kNullProcessId);
    320         LOG(ERROR) << "Plug-in crashed on start";
    321 
    322         // Return true so that the plugin widget is created and we can paint the
    323         // crashed plugin there.
    324         return true;
    325       }
    326       LOG(ERROR) << "Plug-in couldn't be found";
    327       return false;
    328     }
    329 
    330     channel_host =
    331         PluginChannelHost::GetPluginChannelHost(
    332             channel_handle, ChildProcess::current()->io_message_loop_proxy());
    333     if (!channel_host.get()) {
    334       LOG(ERROR) << "Couldn't get PluginChannelHost";
    335       continue;
    336     }
    337 #if defined(OS_MACOSX)
    338     track_nested_removes.reset();
    339 #endif
    340 
    341     {
    342       // TODO(bauerb): Debugging for http://crbug.com/141055.
    343       ScopedLogLevel log_level(-2);  // Equivalent to --v=2
    344       result = channel_host->Send(new PluginMsg_CreateInstance(
    345           mime_type_, &instance_id));
    346       if (!result) {
    347         LOG(ERROR) << "Couldn't send PluginMsg_CreateInstance";
    348         continue;
    349       }
    350     }
    351   }
    352 
    353   // Failed too often, give up.
    354   if (!result)
    355     return false;
    356 
    357   channel_host_ = channel_host;
    358   instance_id_ = instance_id;
    359 
    360   channel_host_->AddRoute(instance_id_, this, NULL);
    361 
    362   // Inform the channel of the mapping between our instance-Id and dummy NPP
    363   // identifier, for use in object ownership tracking.
    364   channel_host_->AddMappingForNPObjectOwner(instance_id_, GetPluginNPP());
    365 
    366   // Now tell the PluginInstance in the plugin process to initialize.
    367   PluginMsg_Init_Params params;
    368   params.url = url;
    369   params.page_url = page_url_;
    370   params.arg_names = arg_names;
    371   params.arg_values = arg_values;
    372   params.host_render_view_routing_id = render_view_->routing_id();
    373   params.load_manually = load_manually;
    374 
    375   plugin_ = plugin;
    376 
    377   result = false;
    378   Send(new PluginMsg_Init(instance_id_, params, &transparent_, &result));
    379 
    380   if (!result)
    381     LOG(ERROR) << "PluginMsg_Init returned false";
    382 
    383   render_view_->RegisterPluginDelegate(this);
    384 
    385   return result;
    386 }
    387 
    388 bool WebPluginDelegateProxy::Send(IPC::Message* msg) {
    389   if (!channel_host_.get()) {
    390     DLOG(WARNING) << "dropping message because channel host is null";
    391     delete msg;
    392     return false;
    393   }
    394 
    395   return channel_host_->Send(msg);
    396 }
    397 
    398 void WebPluginDelegateProxy::SendJavaScriptStream(const GURL& url,
    399                                                   const std::string& result,
    400                                                   bool success,
    401                                                   int notify_id) {
    402   Send(new PluginMsg_SendJavaScriptStream(
    403       instance_id_, url, result, success, notify_id));
    404 }
    405 
    406 void WebPluginDelegateProxy::DidReceiveManualResponse(
    407     const GURL& url, const std::string& mime_type,
    408     const std::string& headers, uint32 expected_length,
    409     uint32 last_modified) {
    410   PluginMsg_DidReceiveResponseParams params;
    411   params.id = 0;
    412   params.mime_type = mime_type;
    413   params.headers = headers;
    414   params.expected_length = expected_length;
    415   params.last_modified = last_modified;
    416   Send(new PluginMsg_DidReceiveManualResponse(instance_id_, url, params));
    417 }
    418 
    419 void WebPluginDelegateProxy::DidReceiveManualData(const char* buffer,
    420                                                   int length) {
    421   DCHECK_GT(length, 0);
    422   std::vector<char> data;
    423   data.resize(static_cast<size_t>(length));
    424   memcpy(&data.front(), buffer, length);
    425   Send(new PluginMsg_DidReceiveManualData(instance_id_, data));
    426 }
    427 
    428 void WebPluginDelegateProxy::DidFinishManualLoading() {
    429   Send(new PluginMsg_DidFinishManualLoading(instance_id_));
    430 }
    431 
    432 void WebPluginDelegateProxy::DidManualLoadFail() {
    433   Send(new PluginMsg_DidManualLoadFail(instance_id_));
    434 }
    435 
    436 bool WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) {
    437   GetContentClient()->SetActiveURL(page_url_);
    438 
    439   bool handled = true;
    440   IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateProxy, msg)
    441     IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindow, OnSetWindow)
    442 #if defined(OS_WIN)
    443     IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindowlessData, OnSetWindowlessData)
    444     IPC_MESSAGE_HANDLER(PluginHostMsg_NotifyIMEStatus, OnNotifyIMEStatus)
    445 #endif
    446     IPC_MESSAGE_HANDLER(PluginHostMsg_CancelResource, OnCancelResource)
    447     IPC_MESSAGE_HANDLER(PluginHostMsg_InvalidateRect, OnInvalidateRect)
    448     IPC_MESSAGE_HANDLER(PluginHostMsg_GetWindowScriptNPObject,
    449                         OnGetWindowScriptNPObject)
    450     IPC_MESSAGE_HANDLER(PluginHostMsg_GetPluginElement, OnGetPluginElement)
    451     IPC_MESSAGE_HANDLER(PluginHostMsg_ResolveProxy, OnResolveProxy)
    452     IPC_MESSAGE_HANDLER(PluginHostMsg_SetCookie, OnSetCookie)
    453     IPC_MESSAGE_HANDLER(PluginHostMsg_GetCookies, OnGetCookies)
    454     IPC_MESSAGE_HANDLER(PluginHostMsg_URLRequest, OnHandleURLRequest)
    455     IPC_MESSAGE_HANDLER(PluginHostMsg_CancelDocumentLoad, OnCancelDocumentLoad)
    456     IPC_MESSAGE_HANDLER(PluginHostMsg_InitiateHTTPRangeRequest,
    457                         OnInitiateHTTPRangeRequest)
    458     IPC_MESSAGE_HANDLER(PluginHostMsg_DeferResourceLoading,
    459                         OnDeferResourceLoading)
    460 
    461 #if defined(OS_MACOSX)
    462     IPC_MESSAGE_HANDLER(PluginHostMsg_FocusChanged,
    463                         OnFocusChanged);
    464     IPC_MESSAGE_HANDLER(PluginHostMsg_StartIme,
    465                         OnStartIme);
    466     IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedPluginEnabledRendering,
    467                         OnAcceleratedPluginEnabledRendering)
    468     IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedPluginAllocatedIOSurface,
    469                         OnAcceleratedPluginAllocatedIOSurface)
    470     IPC_MESSAGE_HANDLER(PluginHostMsg_AcceleratedPluginSwappedIOSurface,
    471                         OnAcceleratedPluginSwappedIOSurface)
    472 #endif
    473     IPC_MESSAGE_HANDLER(PluginHostMsg_URLRedirectResponse,
    474                         OnURLRedirectResponse)
    475     IPC_MESSAGE_UNHANDLED(handled = false)
    476   IPC_END_MESSAGE_MAP()
    477   DCHECK(handled);
    478   return handled;
    479 }
    480 
    481 void WebPluginDelegateProxy::OnChannelError() {
    482   if (plugin_) {
    483     if (window_) {
    484       // The actual WebPluginDelegate never got a chance to tell the WebPlugin
    485       // its window was going away. Do it on its behalf.
    486       WillDestroyWindow();
    487     }
    488     plugin_->Invalidate();
    489   }
    490   if (!channel_host_->expecting_shutdown())
    491     render_view_->PluginCrashed(info_.path, channel_host_->peer_pid());
    492 
    493 #if defined(OS_MACOSX) || defined(OS_WIN)
    494   // Ensure that the renderer doesn't think the plugin still has focus.
    495   if (render_view_)
    496     render_view_->PluginFocusChanged(false, instance_id_);
    497 #endif
    498 }
    499 
    500 static void CopyTransportDIBHandleForMessage(
    501     const TransportDIB::Handle& handle_in,
    502     TransportDIB::Handle* handle_out,
    503     base::ProcessId peer_pid) {
    504 #if defined(OS_MACOSX)
    505   // On Mac, TransportDIB::Handle is typedef'ed to FileDescriptor, and
    506   // FileDescriptor message fields needs to remain valid until the message is
    507   // sent or else the sendmsg() call will fail.
    508   if ((handle_out->fd = HANDLE_EINTR(dup(handle_in.fd))) < 0) {
    509     PLOG(ERROR) << "dup()";
    510     return;
    511   }
    512   handle_out->auto_close = true;
    513 #elif defined(OS_WIN)
    514   // On Windows we need to duplicate the handle for the plugin process.
    515   *handle_out = NULL;
    516   BrokerDuplicateHandle(handle_in, peer_pid, handle_out,
    517                         FILE_MAP_READ | FILE_MAP_WRITE, 0);
    518   DCHECK(*handle_out != NULL);
    519 #else
    520   // Don't need to do anything special for other platforms.
    521   *handle_out = handle_in;
    522 #endif
    523 }
    524 
    525 void WebPluginDelegateProxy::SendUpdateGeometry(
    526     bool bitmaps_changed) {
    527   PluginMsg_UpdateGeometry_Param param;
    528   param.window_rect = plugin_rect_;
    529   param.clip_rect = clip_rect_;
    530   param.windowless_buffer0 = TransportDIB::DefaultHandleValue();
    531   param.windowless_buffer1 = TransportDIB::DefaultHandleValue();
    532   param.windowless_buffer_index = back_buffer_index();
    533 
    534 #if defined(OS_POSIX)
    535   // If we're using POSIX mmap'd TransportDIBs, sending the handle across
    536   // IPC establishes a new mapping rather than just sending a window ID,
    537   // so only do so if we've actually changed the shared memory bitmaps.
    538   if (bitmaps_changed)
    539 #endif
    540   {
    541     if (transport_stores_[0].dib)
    542       CopyTransportDIBHandleForMessage(transport_stores_[0].dib->handle(),
    543                                        &param.windowless_buffer0,
    544                                        channel_host_->peer_pid());
    545 
    546     if (transport_stores_[1].dib)
    547       CopyTransportDIBHandleForMessage(transport_stores_[1].dib->handle(),
    548                                        &param.windowless_buffer1,
    549                                        channel_host_->peer_pid());
    550   }
    551 
    552   IPC::Message* msg;
    553 #if defined(OS_WIN)
    554   if (UseSynchronousGeometryUpdates()) {
    555     msg = new PluginMsg_UpdateGeometrySync(instance_id_, param);
    556   } else  // NOLINT
    557 #endif
    558   {
    559     msg = new PluginMsg_UpdateGeometry(instance_id_, param);
    560     msg->set_unblock(true);
    561   }
    562 
    563   Send(msg);
    564 }
    565 
    566 void WebPluginDelegateProxy::UpdateGeometry(const gfx::Rect& window_rect,
    567                                             const gfx::Rect& clip_rect) {
    568   // window_rect becomes either a window in native windowing system
    569   // coords, or a backing buffer.  In either case things will go bad
    570   // if the rectangle is very large.
    571   if (window_rect.width() < 0  || window_rect.width() > kMaxPluginSideLength ||
    572       window_rect.height() < 0 || window_rect.height() > kMaxPluginSideLength ||
    573       // We know this won't overflow due to above checks.
    574       static_cast<uint32>(window_rect.width()) *
    575           static_cast<uint32>(window_rect.height()) > kMaxPluginSize) {
    576     return;
    577   }
    578 
    579   plugin_rect_ = window_rect;
    580   clip_rect_ = clip_rect;
    581 
    582   bool bitmaps_changed = false;
    583 
    584   if (uses_shared_bitmaps_) {
    585     if (!front_buffer_canvas() ||
    586         (window_rect.width() != front_buffer_canvas()->getDevice()->width() ||
    587          window_rect.height() != front_buffer_canvas()->getDevice()->height()))
    588     {
    589       bitmaps_changed = true;
    590 
    591       // Create a shared memory section that the plugin paints into
    592       // asynchronously.
    593       ResetWindowlessBitmaps();
    594       if (!window_rect.IsEmpty()) {
    595         if (!CreateSharedBitmap(&transport_stores_[0].dib,
    596                                 &transport_stores_[0].canvas) ||
    597             !CreateSharedBitmap(&transport_stores_[1].dib,
    598                                 &transport_stores_[1].canvas)) {
    599           DCHECK(false);
    600           ResetWindowlessBitmaps();
    601           return;
    602         }
    603       }
    604     }
    605   }
    606 
    607   SendUpdateGeometry(bitmaps_changed);
    608 }
    609 
    610 void WebPluginDelegateProxy::ResetWindowlessBitmaps() {
    611   transport_stores_[0].dib.reset();
    612   transport_stores_[1].dib.reset();
    613 
    614   transport_stores_[0].canvas.reset();
    615   transport_stores_[1].canvas.reset();
    616   transport_store_painted_ = gfx::Rect();
    617   front_buffer_diff_ = gfx::Rect();
    618 }
    619 
    620 static size_t BitmapSizeForPluginRect(const gfx::Rect& plugin_rect) {
    621   const size_t stride =
    622       skia::PlatformCanvasStrideForWidth(plugin_rect.width());
    623   return stride * plugin_rect.height();
    624 }
    625 
    626 #if !defined(OS_WIN)
    627 bool WebPluginDelegateProxy::CreateLocalBitmap(
    628     std::vector<uint8>* memory,
    629     scoped_ptr<skia::PlatformCanvas>* canvas) {
    630   const size_t size = BitmapSizeForPluginRect(plugin_rect_);
    631   memory->resize(size);
    632   if (memory->size() != size)
    633     return false;
    634   canvas->reset(skia::CreatePlatformCanvas(
    635       plugin_rect_.width(), plugin_rect_.height(), true, &((*memory)[0]),
    636       skia::CRASH_ON_FAILURE));
    637   return true;
    638 }
    639 #endif
    640 
    641 bool WebPluginDelegateProxy::CreateSharedBitmap(
    642     scoped_ptr<TransportDIB>* memory,
    643     scoped_ptr<skia::PlatformCanvas>* canvas) {
    644   const size_t size = BitmapSizeForPluginRect(plugin_rect_);
    645 #if defined(OS_POSIX) && !defined(OS_MACOSX)
    646   memory->reset(TransportDIB::Create(size, 0));
    647   if (!memory->get())
    648     return false;
    649 #endif
    650 #if defined(OS_POSIX) && !defined(TOOLKIT_GTK) && !defined(OS_ANDROID)
    651   TransportDIB::Handle handle;
    652   IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, false, &handle);
    653   if (!RenderThreadImpl::current()->Send(msg))
    654     return false;
    655   if (handle.fd < 0)
    656     return false;
    657   memory->reset(TransportDIB::Map(handle));
    658 #else
    659   static uint32 sequence_number = 0;
    660   memory->reset(TransportDIB::Create(size, sequence_number++));
    661 #endif
    662   canvas->reset((*memory)->GetPlatformCanvas(plugin_rect_.width(),
    663                                              plugin_rect_.height()));
    664   return !!canvas->get();
    665 }
    666 
    667 #if defined(OS_MACOSX)
    668 // Flips |rect| vertically within an enclosing rect with height |height|.
    669 // Intended for converting rects between flipped and non-flipped contexts.
    670 static void FlipRectVerticallyWithHeight(gfx::Rect* rect, int height) {
    671   rect->set_y(height - rect->bottom());
    672 }
    673 #endif
    674 
    675 void WebPluginDelegateProxy::Paint(WebKit::WebCanvas* canvas,
    676                                    const gfx::Rect& damaged_rect) {
    677   // Limit the damaged rectangle to whatever is contained inside the plugin
    678   // rectangle, as that's the rectangle that we'll actually draw.
    679   gfx::Rect rect = gfx::IntersectRects(damaged_rect, plugin_rect_);
    680 
    681   // If the plugin is no longer connected (channel crashed) draw a crashed
    682   // plugin bitmap
    683   if (!channel_host_.get() || !channel_host_->channel_valid()) {
    684     // Lazily load the sad plugin image.
    685     if (!sad_plugin_)
    686       sad_plugin_ = GetContentClient()->renderer()->GetSadPluginBitmap();
    687     if (sad_plugin_)
    688       PaintSadPlugin(canvas, plugin_rect_, *sad_plugin_);
    689     return;
    690   }
    691 
    692   if (!uses_shared_bitmaps_)
    693     return;
    694 
    695   // We got a paint before the plugin's coordinates, so there's no buffer to
    696   // copy from.
    697   if (!front_buffer_canvas())
    698     return;
    699 
    700   gfx::Rect offset_rect = rect;
    701   offset_rect.Offset(-plugin_rect_.x(), -plugin_rect_.y());
    702 
    703   // transport_store_painted_ is really a bounding box, so in principle this
    704   // check could falsely indicate that we don't need to paint offset_rect, but
    705   // in practice it works fine.
    706   if (!transport_store_painted_.Contains(offset_rect)) {
    707     Send(new PluginMsg_Paint(instance_id_, offset_rect));
    708     // Since the plugin is not blocked on the renderer in this context, there is
    709     // a chance that it will begin repainting the back-buffer before we complete
    710     // capturing the data. Buffer flipping would increase that risk because
    711     // geometry update is asynchronous, so we don't want to use buffer flipping
    712     // here.
    713     UpdateFrontBuffer(offset_rect, false);
    714   }
    715 
    716   const SkBitmap& bitmap =
    717       front_buffer_canvas()->getDevice()->accessBitmap(false);
    718   SkPaint paint;
    719   paint.setXfermodeMode(
    720       transparent_ ? SkXfermode::kSrcATop_Mode : SkXfermode::kSrc_Mode);
    721   SkIRect src_rect = gfx::RectToSkIRect(offset_rect);
    722   canvas->drawBitmapRect(bitmap,
    723                          &src_rect,
    724                          gfx::RectToSkRect(rect),
    725                          &paint);
    726 
    727   if (invalidate_pending_) {
    728     // Only send the PaintAck message if this paint is in response to an
    729     // invalidate from the plugin, since this message acts as an access token
    730     // to ensure only one process is using the transport dib at a time.
    731     invalidate_pending_ = false;
    732     Send(new PluginMsg_DidPaint(instance_id_));
    733   }
    734 }
    735 
    736 NPObject* WebPluginDelegateProxy::GetPluginScriptableObject() {
    737   if (npobject_)
    738     return WebBindings::retainObject(npobject_);
    739 
    740   int route_id = MSG_ROUTING_NONE;
    741   Send(new PluginMsg_GetPluginScriptableObject(instance_id_, &route_id));
    742   if (route_id == MSG_ROUTING_NONE)
    743     return NULL;
    744 
    745   npobject_ = NPObjectProxy::Create(
    746       channel_host_.get(), route_id, 0, page_url_, GetPluginNPP());
    747 
    748   return WebBindings::retainObject(npobject_);
    749 }
    750 
    751 NPP WebPluginDelegateProxy::GetPluginNPP() {
    752   // Return a dummy NPP for WebKit to use to identify this plugin.
    753   return npp_.get();
    754 }
    755 
    756 bool WebPluginDelegateProxy::GetFormValue(string16* value) {
    757   bool success = false;
    758   Send(new PluginMsg_GetFormValue(instance_id_, value, &success));
    759   return success;
    760 }
    761 
    762 void WebPluginDelegateProxy::DidFinishLoadWithReason(
    763     const GURL& url, NPReason reason, int notify_id) {
    764   Send(new PluginMsg_DidFinishLoadWithReason(
    765       instance_id_, url, reason, notify_id));
    766 }
    767 
    768 void WebPluginDelegateProxy::SetFocus(bool focused) {
    769   Send(new PluginMsg_SetFocus(instance_id_, focused));
    770 #if defined(OS_WIN)
    771   if (render_view_)
    772     render_view_->PluginFocusChanged(focused, instance_id_);
    773 #endif
    774 }
    775 
    776 bool WebPluginDelegateProxy::HandleInputEvent(
    777     const WebInputEvent& event,
    778     WebCursor::CursorInfo* cursor_info) {
    779   bool handled;
    780   WebCursor cursor;
    781   // A windowless plugin can enter a modal loop in the context of a
    782   // NPP_HandleEvent call, in which case we need to pump messages to
    783   // the plugin. We pass of the corresponding event handle to the
    784   // plugin process, which is set if the plugin does enter a modal loop.
    785   IPC::SyncMessage* message = new PluginMsg_HandleInputEvent(
    786       instance_id_, &event, &handled, &cursor);
    787   message->set_pump_messages_event(modal_loop_pump_messages_event_.get());
    788   Send(message);
    789   return handled;
    790 }
    791 
    792 int WebPluginDelegateProxy::GetProcessId() {
    793   return channel_host_->peer_pid();
    794 }
    795 
    796 void WebPluginDelegateProxy::SetContentAreaFocus(bool has_focus) {
    797   IPC::Message* msg = new PluginMsg_SetContentAreaFocus(instance_id_,
    798                                                         has_focus);
    799   // Make sure focus events are delivered in the right order relative to
    800   // sync messages they might interact with (Paint, HandleEvent, etc.).
    801   msg->set_unblock(true);
    802   Send(msg);
    803 }
    804 
    805 #if defined(OS_WIN)
    806 void WebPluginDelegateProxy::ImeCompositionUpdated(
    807     const string16& text,
    808     const std::vector<int>& clauses,
    809     const std::vector<int>& target,
    810     int cursor_position,
    811     int plugin_id) {
    812   // Dispatch the raw IME data if this plug-in is the focused one.
    813   if (instance_id_ != plugin_id)
    814     return;
    815 
    816   IPC::Message* msg = new PluginMsg_ImeCompositionUpdated(instance_id_,
    817       text, clauses, target, cursor_position);
    818   msg->set_unblock(true);
    819   Send(msg);
    820 }
    821 
    822 void WebPluginDelegateProxy::ImeCompositionCompleted(const string16& text,
    823                                                      int plugin_id) {
    824   // Dispatch the IME text if this plug-in is the focused one.
    825   if (instance_id_ != plugin_id)
    826     return;
    827 
    828   IPC::Message* msg = new PluginMsg_ImeCompositionCompleted(instance_id_, text);
    829   msg->set_unblock(true);
    830   Send(msg);
    831 }
    832 #endif
    833 
    834 #if defined(OS_MACOSX)
    835 void WebPluginDelegateProxy::SetWindowFocus(bool window_has_focus) {
    836   IPC::Message* msg = new PluginMsg_SetWindowFocus(instance_id_,
    837                                                    window_has_focus);
    838   // Make sure focus events are delivered in the right order relative to
    839   // sync messages they might interact with (Paint, HandleEvent, etc.).
    840   msg->set_unblock(true);
    841   Send(msg);
    842 }
    843 
    844 void WebPluginDelegateProxy::SetContainerVisibility(bool is_visible) {
    845   IPC::Message* msg;
    846   if (is_visible) {
    847     gfx::Rect window_frame = render_view_->rootWindowRect();
    848     gfx::Rect view_frame = render_view_->windowRect();
    849     WebKit::WebView* webview = render_view_->webview();
    850     msg = new PluginMsg_ContainerShown(instance_id_, window_frame, view_frame,
    851                                        webview && webview->isActive());
    852   } else {
    853     msg = new PluginMsg_ContainerHidden(instance_id_);
    854   }
    855   // Make sure visibility events are delivered in the right order relative to
    856   // sync messages they might interact with (Paint, HandleEvent, etc.).
    857   msg->set_unblock(true);
    858   Send(msg);
    859 }
    860 
    861 void WebPluginDelegateProxy::WindowFrameChanged(gfx::Rect window_frame,
    862                                                 gfx::Rect view_frame) {
    863   IPC::Message* msg = new PluginMsg_WindowFrameChanged(instance_id_,
    864                                                        window_frame,
    865                                                        view_frame);
    866   // Make sure frame events are delivered in the right order relative to
    867   // sync messages they might interact with (e.g., HandleEvent).
    868   msg->set_unblock(true);
    869   Send(msg);
    870 }
    871 void WebPluginDelegateProxy::ImeCompositionCompleted(const string16& text,
    872                                                      int plugin_id) {
    873   // If the message isn't intended for this plugin, there's nothing to do.
    874   if (instance_id_ != plugin_id)
    875     return;
    876 
    877   IPC::Message* msg = new PluginMsg_ImeCompositionCompleted(instance_id_,
    878                                                             text);
    879   // Order relative to other key events is important.
    880   msg->set_unblock(true);
    881   Send(msg);
    882 }
    883 #endif  // OS_MACOSX
    884 
    885 void WebPluginDelegateProxy::OnSetWindow(gfx::PluginWindowHandle window) {
    886 #if defined(OS_MACOSX)
    887   uses_shared_bitmaps_ = !window && !uses_compositor_;
    888 #else
    889   uses_shared_bitmaps_ = !window;
    890 #endif
    891   window_ = window;
    892   if (plugin_)
    893     plugin_->SetWindow(window);
    894 }
    895 
    896 void WebPluginDelegateProxy::WillDestroyWindow() {
    897   DCHECK(window_);
    898   plugin_->WillDestroyWindow(window_);
    899   window_ = gfx::kNullPluginWindow;
    900 }
    901 
    902 #if defined(OS_WIN)
    903 void WebPluginDelegateProxy::OnSetWindowlessData(
    904       HANDLE modal_loop_pump_messages_event,
    905       gfx::NativeViewId dummy_activation_window) {
    906   DCHECK(modal_loop_pump_messages_event_ == NULL);
    907   DCHECK(dummy_activation_window_ == NULL);
    908 
    909   dummy_activation_window_ = dummy_activation_window;
    910   render_view_->Send(new ViewHostMsg_WindowlessPluginDummyWindowCreated(
    911       render_view_->routing_id(), dummy_activation_window_));
    912 
    913   // Bug 25583: this can be null because some "virus scanners" block the
    914   // DuplicateHandle call in the plugin process.
    915   if (!modal_loop_pump_messages_event)
    916     return;
    917 
    918   modal_loop_pump_messages_event_.reset(
    919       new base::WaitableEvent(modal_loop_pump_messages_event));
    920 }
    921 
    922 void WebPluginDelegateProxy::OnNotifyIMEStatus(int input_type,
    923                                                const gfx::Rect& caret_rect) {
    924   if (!render_view_)
    925     return;
    926 
    927   render_view_->Send(new ViewHostMsg_TextInputTypeChanged(
    928       render_view_->routing_id(),
    929       static_cast<ui::TextInputType>(input_type),
    930       true,
    931       ui::TEXT_INPUT_MODE_DEFAULT));
    932 
    933   ViewHostMsg_SelectionBounds_Params bounds_params;
    934   bounds_params.anchor_rect = bounds_params.focus_rect = caret_rect;
    935   bounds_params.anchor_dir = bounds_params.focus_dir =
    936       WebKit::WebTextDirectionLeftToRight;
    937   bounds_params.is_anchor_first = true;
    938   render_view_->Send(new ViewHostMsg_SelectionBoundsChanged(
    939       render_view_->routing_id(),
    940       bounds_params));
    941 }
    942 #endif
    943 
    944 void WebPluginDelegateProxy::OnCancelResource(int id) {
    945   if (plugin_)
    946     plugin_->CancelResource(id);
    947 }
    948 
    949 void WebPluginDelegateProxy::OnInvalidateRect(const gfx::Rect& rect) {
    950   if (!plugin_)
    951     return;
    952 
    953   // Clip the invalidation rect to the plugin bounds; the plugin may have been
    954   // resized since the invalidate message was sent.
    955   gfx::Rect clipped_rect =
    956       gfx::IntersectRects(rect, gfx::Rect(plugin_rect_.size()));
    957 
    958   invalidate_pending_ = true;
    959   // The plugin is blocked on the renderer because the invalidate message it has
    960   // sent us is synchronous, so we can use buffer flipping here if the caller
    961   // allows it.
    962   UpdateFrontBuffer(clipped_rect, true);
    963   plugin_->InvalidateRect(clipped_rect);
    964 }
    965 
    966 void WebPluginDelegateProxy::OnGetWindowScriptNPObject(
    967     int route_id, bool* success) {
    968   *success = false;
    969   NPObject* npobject = NULL;
    970   if (plugin_)
    971     npobject = plugin_->GetWindowScriptNPObject();
    972 
    973   if (!npobject)
    974     return;
    975 
    976   // The stub will delete itself when the proxy tells it that it's released, or
    977   // otherwise when the channel is closed.
    978   new NPObjectStub(npobject, channel_host_.get(), route_id, 0, page_url_);
    979   *success = true;
    980 }
    981 
    982 void WebPluginDelegateProxy::OnResolveProxy(const GURL& url,
    983                                             bool* result,
    984                                             std::string* proxy_list) {
    985   *result = RenderThreadImpl::current()->ResolveProxy(url, proxy_list);
    986 }
    987 
    988 void WebPluginDelegateProxy::OnGetPluginElement(int route_id, bool* success) {
    989   *success = false;
    990   NPObject* npobject = NULL;
    991   if (plugin_)
    992     npobject = plugin_->GetPluginElement();
    993   if (!npobject)
    994     return;
    995 
    996   // The stub will delete itself when the proxy tells it that it's released, or
    997   // otherwise when the channel is closed.
    998   new NPObjectStub(
    999       npobject, channel_host_.get(), route_id, 0, page_url_);
   1000   *success = true;
   1001 }
   1002 
   1003 void WebPluginDelegateProxy::OnSetCookie(const GURL& url,
   1004                                          const GURL& first_party_for_cookies,
   1005                                          const std::string& cookie) {
   1006   if (plugin_)
   1007     plugin_->SetCookie(url, first_party_for_cookies, cookie);
   1008 }
   1009 
   1010 void WebPluginDelegateProxy::OnGetCookies(const GURL& url,
   1011                                           const GURL& first_party_for_cookies,
   1012                                           std::string* cookies) {
   1013   DCHECK(cookies);
   1014   if (plugin_)
   1015     *cookies = plugin_->GetCookies(url, first_party_for_cookies);
   1016 }
   1017 
   1018 void WebPluginDelegateProxy::CopyFromBackBufferToFrontBuffer(
   1019     const gfx::Rect& rect) {
   1020 #if defined(OS_MACOSX)
   1021   // Blitting the bits directly is much faster than going through CG, and since
   1022   // the goal is just to move the raw pixels between two bitmaps with the same
   1023   // pixel format (no compositing, color correction, etc.), it's safe.
   1024   const size_t stride =
   1025       skia::PlatformCanvasStrideForWidth(plugin_rect_.width());
   1026   const size_t chunk_size = 4 * rect.width();
   1027   DCHECK(back_buffer_dib() != NULL);
   1028   uint8* source_data = static_cast<uint8*>(back_buffer_dib()->memory()) +
   1029                        rect.y() * stride + 4 * rect.x();
   1030   DCHECK(front_buffer_dib() != NULL);
   1031   uint8* target_data = static_cast<uint8*>(front_buffer_dib()->memory()) +
   1032                        rect.y() * stride + 4 * rect.x();
   1033   for (int row = 0; row < rect.height(); ++row) {
   1034     memcpy(target_data, source_data, chunk_size);
   1035     source_data += stride;
   1036     target_data += stride;
   1037   }
   1038 #else
   1039   BlitCanvasToCanvas(front_buffer_canvas(),
   1040                      rect,
   1041                      back_buffer_canvas(),
   1042                      rect.origin());
   1043 #endif
   1044 }
   1045 
   1046 void WebPluginDelegateProxy::UpdateFrontBuffer(
   1047     const gfx::Rect& rect,
   1048     bool allow_buffer_flipping) {
   1049   if (!front_buffer_canvas()) {
   1050     return;
   1051   }
   1052 
   1053 #if defined(OS_WIN)
   1054   // If SendUpdateGeometry() would block on the plugin process then we don't
   1055   // want to use buffer flipping at all since it would add extra locking.
   1056   // (Alternatively we could probably safely use async updates for buffer
   1057   // flipping all the time since the size is not changing.)
   1058   if (UseSynchronousGeometryUpdates()) {
   1059     allow_buffer_flipping = false;
   1060   }
   1061 #endif
   1062 
   1063   // Plugin has just painted "rect" into the back-buffer, so the front-buffer
   1064   // no longer holds the latest content for that rectangle.
   1065   front_buffer_diff_.Subtract(rect);
   1066   if (allow_buffer_flipping && front_buffer_diff_.IsEmpty()) {
   1067     // Back-buffer contains the latest content for all areas; simply flip
   1068     // the buffers.
   1069     front_buffer_index_ = back_buffer_index();
   1070     SendUpdateGeometry(false);
   1071     // The front-buffer now holds newer content for this region than the
   1072     // back-buffer.
   1073     front_buffer_diff_ = rect;
   1074   } else {
   1075     // Back-buffer contains the latest content for "rect" but the front-buffer
   1076     // contains the latest content for some other areas (or buffer flipping not
   1077     // allowed); fall back to copying the data.
   1078     CopyFromBackBufferToFrontBuffer(rect);
   1079   }
   1080   transport_store_painted_.Union(rect);
   1081 }
   1082 
   1083 void WebPluginDelegateProxy::OnHandleURLRequest(
   1084     const PluginHostMsg_URLRequest_Params& params) {
   1085   const char* data = NULL;
   1086   if (params.buffer.size())
   1087     data = &params.buffer[0];
   1088 
   1089   const char* target = NULL;
   1090   if (params.target.length())
   1091     target = params.target.c_str();
   1092 
   1093   plugin_->HandleURLRequest(
   1094       params.url.c_str(), params.method.c_str(), target, data,
   1095       static_cast<unsigned int>(params.buffer.size()), params.notify_id,
   1096       params.popups_allowed, params.notify_redirects);
   1097 }
   1098 
   1099 WebPluginResourceClient* WebPluginDelegateProxy::CreateResourceClient(
   1100     unsigned long resource_id, const GURL& url, int notify_id) {
   1101   if (!channel_host_.get())
   1102     return NULL;
   1103 
   1104   ResourceClientProxy* proxy =
   1105       new ResourceClientProxy(channel_host_.get(), instance_id_);
   1106   proxy->Initialize(resource_id, url, notify_id);
   1107   return proxy;
   1108 }
   1109 
   1110 WebPluginResourceClient* WebPluginDelegateProxy::CreateSeekableResourceClient(
   1111     unsigned long resource_id, int range_request_id) {
   1112   if (!channel_host_.get())
   1113     return NULL;
   1114 
   1115   ResourceClientProxy* proxy =
   1116       new ResourceClientProxy(channel_host_.get(), instance_id_);
   1117   proxy->InitializeForSeekableStream(resource_id, range_request_id);
   1118   return proxy;
   1119 }
   1120 
   1121 #if defined(OS_MACOSX)
   1122 void WebPluginDelegateProxy::OnFocusChanged(bool focused) {
   1123   if (render_view_)
   1124     render_view_->PluginFocusChanged(focused, instance_id_);
   1125 }
   1126 
   1127 void WebPluginDelegateProxy::OnStartIme() {
   1128   if (render_view_)
   1129     render_view_->StartPluginIme();
   1130 }
   1131 #endif
   1132 
   1133 gfx::PluginWindowHandle WebPluginDelegateProxy::GetPluginWindowHandle() {
   1134   return window_;
   1135 }
   1136 
   1137 void WebPluginDelegateProxy::OnCancelDocumentLoad() {
   1138   plugin_->CancelDocumentLoad();
   1139 }
   1140 
   1141 void WebPluginDelegateProxy::OnInitiateHTTPRangeRequest(
   1142     const std::string& url,
   1143     const std::string& range_info,
   1144     int range_request_id) {
   1145   plugin_->InitiateHTTPRangeRequest(
   1146       url.c_str(), range_info.c_str(), range_request_id);
   1147 }
   1148 
   1149 void WebPluginDelegateProxy::OnDeferResourceLoading(unsigned long resource_id,
   1150                                                     bool defer) {
   1151   plugin_->SetDeferResourceLoading(resource_id, defer);
   1152 }
   1153 
   1154 #if defined(OS_MACOSX)
   1155 void WebPluginDelegateProxy::OnAcceleratedPluginEnabledRendering() {
   1156   uses_compositor_ = true;
   1157   OnSetWindow(gfx::kNullPluginWindow);
   1158 }
   1159 
   1160 void WebPluginDelegateProxy::OnAcceleratedPluginAllocatedIOSurface(
   1161     int32 width,
   1162     int32 height,
   1163     uint32 surface_id) {
   1164   if (plugin_)
   1165     plugin_->AcceleratedPluginAllocatedIOSurface(width, height, surface_id);
   1166 }
   1167 
   1168 void WebPluginDelegateProxy::OnAcceleratedPluginSwappedIOSurface() {
   1169   if (plugin_)
   1170     plugin_->AcceleratedPluginSwappedIOSurface();
   1171 }
   1172 #endif
   1173 
   1174 #if defined(OS_WIN)
   1175 bool WebPluginDelegateProxy::UseSynchronousGeometryUpdates() {
   1176   // Need to update geometry synchronously with WMP, otherwise if a site
   1177   // scripts the plugin to start playing while it's in the middle of handling
   1178   // an update geometry message, videos don't play.  See urls in bug 20260.
   1179   if (info_.name.find(ASCIIToUTF16("Windows Media Player")) != string16::npos)
   1180     return true;
   1181 
   1182   // The move networks plugin needs to be informed of geometry updates
   1183   // synchronously.
   1184   std::vector<WebPluginMimeType>::iterator index;
   1185   for (index = info_.mime_types.begin(); index != info_.mime_types.end();
   1186        index++) {
   1187     if (index->mime_type == "application/x-vnd.moveplayer.qm" ||
   1188         index->mime_type == "application/x-vnd.moveplay2.qm" ||
   1189         index->mime_type == "application/x-vnd.movenetworks.qm" ||
   1190         index->mime_type == "application/x-vnd.mnplayer.qm") {
   1191       return true;
   1192     }
   1193   }
   1194   return false;
   1195 }
   1196 #endif
   1197 
   1198 void WebPluginDelegateProxy::OnURLRedirectResponse(bool allow,
   1199                                                    int resource_id) {
   1200   if (!plugin_)
   1201     return;
   1202 
   1203   plugin_->URLRedirectResponse(allow, resource_id);
   1204 }
   1205 
   1206 }  // namespace content
   1207