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