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_delegate_stub.h"
      6 
      7 #include "build/build_config.h"
      8 
      9 #include "base/bind.h"
     10 #include "base/command_line.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "content/child/npapi/plugin_instance.h"
     13 #include "content/child/npapi/webplugin_delegate_impl.h"
     14 #include "content/child/plugin_messages.h"
     15 #include "content/plugin/plugin_channel.h"
     16 #include "content/plugin/plugin_thread.h"
     17 #include "content/plugin/webplugin_proxy.h"
     18 #include "content/public/common/content_client.h"
     19 #include "content/public/common/content_constants.h"
     20 #include "content/public/common/content_switches.h"
     21 #include "skia/ext/platform_device.h"
     22 #include "third_party/WebKit/public/web/WebBindings.h"
     23 #include "third_party/WebKit/public/web/WebCursorInfo.h"
     24 #include "third_party/npapi/bindings/npapi.h"
     25 #include "third_party/npapi/bindings/npruntime.h"
     26 #include "webkit/common/cursors/webcursor.h"
     27 
     28 using WebKit::WebBindings;
     29 using WebKit::WebCursorInfo;
     30 
     31 namespace content {
     32 
     33 static void DestroyWebPluginAndDelegate(
     34     base::WeakPtr<NPObjectStub> scriptable_object,
     35     WebPluginDelegateImpl* delegate,
     36     WebPlugin* webplugin) {
     37   // The plugin may not expect us to try to release the scriptable object
     38   // after calling NPP_Destroy on the instance, so delete the stub now.
     39   if (scriptable_object.get())
     40     scriptable_object->DeleteSoon();
     41 
     42   if (delegate) {
     43     // Save the object owner Id so we can unregister it as a valid owner
     44     // after the instance has been destroyed.
     45     NPP owner = delegate->GetPluginNPP();
     46 
     47     // WebPlugin must outlive WebPluginDelegate.
     48     delegate->PluginDestroyed();
     49 
     50     // PluginDestroyed can call into script, so only unregister as an object
     51     // owner after that has completed.
     52     WebBindings::unregisterObjectOwner(owner);
     53   }
     54 
     55   delete webplugin;
     56 }
     57 
     58 WebPluginDelegateStub::WebPluginDelegateStub(
     59     const std::string& mime_type, int instance_id, PluginChannel* channel) :
     60     mime_type_(mime_type),
     61     instance_id_(instance_id),
     62     channel_(channel),
     63     delegate_(NULL),
     64     webplugin_(NULL),
     65     in_destructor_(false) {
     66   DCHECK(channel);
     67 }
     68 
     69 WebPluginDelegateStub::~WebPluginDelegateStub() {
     70   in_destructor_ = true;
     71   GetContentClient()->SetActiveURL(page_url_);
     72 
     73   if (channel_->in_send()) {
     74     // The delegate or an npobject is in the callstack, so don't delete it
     75     // right away.
     76     base::MessageLoop::current()->PostNonNestableTask(
     77         FROM_HERE,
     78         base::Bind(&DestroyWebPluginAndDelegate,
     79                    plugin_scriptable_object_,
     80                    delegate_,
     81                    webplugin_));
     82   } else {
     83     // Safe to delete right away.
     84     DestroyWebPluginAndDelegate(
     85         plugin_scriptable_object_, delegate_, webplugin_);
     86   }
     87 
     88   // Remove the NPObject owner mapping for this instance.
     89   channel_->RemoveMappingForNPObjectOwner(instance_id_);
     90 }
     91 
     92 bool WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) {
     93   GetContentClient()->SetActiveURL(page_url_);
     94 
     95   // A plugin can execute a script to delete itself in any of its NPP methods.
     96   // Hold an extra reference to ourself so that if this does occur and we're
     97   // handling a sync message, we don't crash when attempting to send a reply.
     98   // The exception to this is when we're already in the destructor.
     99   if (!in_destructor_)
    100     AddRef();
    101 
    102   bool handled = true;
    103   IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateStub, msg)
    104     IPC_MESSAGE_HANDLER(PluginMsg_Init, OnInit)
    105     IPC_MESSAGE_HANDLER(PluginMsg_WillSendRequest, OnWillSendRequest)
    106     IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveResponse, OnDidReceiveResponse)
    107     IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveData, OnDidReceiveData)
    108     IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoading, OnDidFinishLoading)
    109     IPC_MESSAGE_HANDLER(PluginMsg_DidFail, OnDidFail)
    110     IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoadWithReason,
    111                         OnDidFinishLoadWithReason)
    112     IPC_MESSAGE_HANDLER(PluginMsg_SetFocus, OnSetFocus)
    113     IPC_MESSAGE_HANDLER(PluginMsg_HandleInputEvent, OnHandleInputEvent)
    114     IPC_MESSAGE_HANDLER(PluginMsg_Paint, OnPaint)
    115     IPC_MESSAGE_HANDLER(PluginMsg_DidPaint, OnDidPaint)
    116     IPC_MESSAGE_HANDLER(PluginMsg_GetPluginScriptableObject,
    117                         OnGetPluginScriptableObject)
    118     IPC_MESSAGE_HANDLER(PluginMsg_GetFormValue, OnGetFormValue)
    119     IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometry, OnUpdateGeometry)
    120     IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometrySync, OnUpdateGeometry)
    121     IPC_MESSAGE_HANDLER(PluginMsg_SendJavaScriptStream,
    122                         OnSendJavaScriptStream)
    123     IPC_MESSAGE_HANDLER(PluginMsg_SetContentAreaFocus, OnSetContentAreaFocus)
    124 #if defined(OS_WIN) && !defined(USE_AURA)
    125     IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionUpdated,
    126                         OnImeCompositionUpdated)
    127     IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionCompleted,
    128                         OnImeCompositionCompleted)
    129 #endif
    130 #if defined(OS_MACOSX)
    131     IPC_MESSAGE_HANDLER(PluginMsg_SetWindowFocus, OnSetWindowFocus)
    132     IPC_MESSAGE_HANDLER(PluginMsg_ContainerHidden, OnContainerHidden)
    133     IPC_MESSAGE_HANDLER(PluginMsg_ContainerShown, OnContainerShown)
    134     IPC_MESSAGE_HANDLER(PluginMsg_WindowFrameChanged, OnWindowFrameChanged)
    135     IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionCompleted,
    136                         OnImeCompositionCompleted)
    137 #endif
    138     IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualResponse,
    139                         OnDidReceiveManualResponse)
    140     IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualData, OnDidReceiveManualData)
    141     IPC_MESSAGE_HANDLER(PluginMsg_DidFinishManualLoading,
    142                         OnDidFinishManualLoading)
    143     IPC_MESSAGE_HANDLER(PluginMsg_DidManualLoadFail, OnDidManualLoadFail)
    144     IPC_MESSAGE_HANDLER(PluginMsg_HandleURLRequestReply,
    145                         OnHandleURLRequestReply)
    146     IPC_MESSAGE_HANDLER(PluginMsg_HTTPRangeRequestReply,
    147                         OnHTTPRangeRequestReply)
    148     IPC_MESSAGE_UNHANDLED(handled = false)
    149   IPC_END_MESSAGE_MAP()
    150 
    151   if (!in_destructor_)
    152     Release();
    153 
    154   DCHECK(handled);
    155   return handled;
    156 }
    157 
    158 bool WebPluginDelegateStub::Send(IPC::Message* msg) {
    159   return channel_->Send(msg);
    160 }
    161 
    162 void WebPluginDelegateStub::OnInit(const PluginMsg_Init_Params& params,
    163                                    bool* transparent,
    164                                    bool* result) {
    165   page_url_ = params.page_url;
    166   GetContentClient()->SetActiveURL(page_url_);
    167 
    168   *transparent = false;
    169   *result = false;
    170   if (params.arg_names.size() != params.arg_values.size()) {
    171     NOTREACHED();
    172     return;
    173   }
    174 
    175   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    176   base::FilePath path =
    177       command_line.GetSwitchValuePath(switches::kPluginPath);
    178 
    179   webplugin_ = new WebPluginProxy(channel_.get(),
    180                                   instance_id_,
    181                                   page_url_,
    182                                   params.host_render_view_routing_id);
    183   delegate_ = WebPluginDelegateImpl::Create(path, mime_type_);
    184   if (delegate_) {
    185     if (delegate_->GetQuirks() &
    186         WebPluginDelegateImpl::PLUGIN_QUIRK_DIE_AFTER_UNLOAD) {
    187       PluginThread::current()->SetForcefullyTerminatePluginProcess();
    188     }
    189 
    190     webplugin_->set_delegate(delegate_);
    191     std::vector<std::string> arg_names = params.arg_names;
    192     std::vector<std::string> arg_values = params.arg_values;
    193 
    194     // Register the plugin as a valid object owner.
    195     WebBindings::registerObjectOwner(delegate_->GetPluginNPP());
    196 
    197     // Add an NPObject owner mapping for this instance, to support ownership
    198     // tracking in the renderer.
    199     channel_->AddMappingForNPObjectOwner(instance_id_,
    200                                          delegate_->GetPluginNPP());
    201 
    202     *result = delegate_->Initialize(params.url,
    203                                     arg_names,
    204                                     arg_values,
    205                                     webplugin_,
    206                                     params.load_manually);
    207     *transparent = delegate_->instance()->transparent();
    208   }
    209 }
    210 
    211 void WebPluginDelegateStub::OnWillSendRequest(int id, const GURL& url,
    212                                               int http_status_code) {
    213   WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
    214   if (!client)
    215     return;
    216 
    217   client->WillSendRequest(url, http_status_code);
    218 }
    219 
    220 void WebPluginDelegateStub::OnDidReceiveResponse(
    221     const PluginMsg_DidReceiveResponseParams& params) {
    222   WebPluginResourceClient* client = webplugin_->GetResourceClient(params.id);
    223   if (!client)
    224     return;
    225 
    226   client->DidReceiveResponse(params.mime_type,
    227                              params.headers,
    228                              params.expected_length,
    229                              params.last_modified,
    230                              params.request_is_seekable);
    231 }
    232 
    233 void WebPluginDelegateStub::OnDidReceiveData(int id,
    234                                              const std::vector<char>& buffer,
    235                                              int data_offset) {
    236   WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
    237   if (!client)
    238     return;
    239 
    240   client->DidReceiveData(&buffer.front(), static_cast<int>(buffer.size()),
    241                          data_offset);
    242 }
    243 
    244 void WebPluginDelegateStub::OnDidFinishLoading(int id) {
    245   WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
    246   if (!client)
    247     return;
    248 
    249   client->DidFinishLoading(id);
    250 }
    251 
    252 void WebPluginDelegateStub::OnDidFail(int id) {
    253   WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
    254   if (!client)
    255     return;
    256 
    257   client->DidFail(id);
    258 }
    259 
    260 void WebPluginDelegateStub::OnDidFinishLoadWithReason(
    261     const GURL& url, int reason, int notify_id) {
    262   delegate_->DidFinishLoadWithReason(url, reason, notify_id);
    263 }
    264 
    265 void WebPluginDelegateStub::OnSetFocus(bool focused) {
    266   delegate_->SetFocus(focused);
    267 #if defined(OS_WIN) && !defined(USE_AURA)
    268   if (focused)
    269     webplugin_->UpdateIMEStatus();
    270 #endif
    271 }
    272 
    273 void WebPluginDelegateStub::OnHandleInputEvent(
    274     const WebKit::WebInputEvent *event,
    275     bool* handled,
    276     WebCursor* cursor) {
    277   WebCursor::CursorInfo cursor_info;
    278   *handled = delegate_->HandleInputEvent(*event, &cursor_info);
    279   cursor->InitFromCursorInfo(cursor_info);
    280 }
    281 
    282 void WebPluginDelegateStub::OnPaint(const gfx::Rect& damaged_rect) {
    283   webplugin_->Paint(damaged_rect);
    284 }
    285 
    286 void WebPluginDelegateStub::OnDidPaint() {
    287   webplugin_->DidPaint();
    288 }
    289 
    290 void WebPluginDelegateStub::OnUpdateGeometry(
    291     const PluginMsg_UpdateGeometry_Param& param) {
    292   webplugin_->UpdateGeometry(
    293       param.window_rect, param.clip_rect,
    294       param.windowless_buffer0, param.windowless_buffer1,
    295       param.windowless_buffer_index);
    296 }
    297 
    298 void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id) {
    299   NPObject* object = delegate_->GetPluginScriptableObject();
    300   if (!object) {
    301     *route_id = MSG_ROUTING_NONE;
    302     return;
    303   }
    304 
    305   *route_id = channel_->GenerateRouteID();
    306   // We will delete the stub immediately before calling PluginDestroyed on the
    307   // delegate. It will delete itself sooner if the proxy tells it that it has
    308   // been released, or if the channel to the proxy is closed.
    309   NPObjectStub* scriptable_stub = new NPObjectStub(
    310       object, channel_.get(), *route_id,
    311       webplugin_->host_render_view_routing_id(), page_url_);
    312   plugin_scriptable_object_ = scriptable_stub->AsWeakPtr();
    313 
    314   // Release ref added by GetPluginScriptableObject (our stub holds its own).
    315   WebBindings::releaseObject(object);
    316 }
    317 
    318 void WebPluginDelegateStub::OnGetFormValue(string16* value, bool* success) {
    319   *success = false;
    320   if (!delegate_)
    321     return;
    322   *success = delegate_->GetFormValue(value);
    323 }
    324 
    325 void WebPluginDelegateStub::OnSendJavaScriptStream(const GURL& url,
    326                                                    const std::string& result,
    327                                                    bool success,
    328                                                    int notify_id) {
    329   delegate_->SendJavaScriptStream(url, result, success, notify_id);
    330 }
    331 
    332 void WebPluginDelegateStub::OnSetContentAreaFocus(bool has_focus) {
    333   if (delegate_)
    334     delegate_->SetContentAreaHasFocus(has_focus);
    335 }
    336 
    337 #if defined(OS_WIN) && !defined(USE_AURA)
    338 void WebPluginDelegateStub::OnImeCompositionUpdated(
    339     const string16& text,
    340     const std::vector<int>& clauses,
    341     const std::vector<int>& target,
    342     int cursor_position) {
    343   if (delegate_)
    344     delegate_->ImeCompositionUpdated(text, clauses, target, cursor_position);
    345 #if defined(OS_WIN) && !defined(USE_AURA)
    346   webplugin_->UpdateIMEStatus();
    347 #endif
    348 }
    349 
    350 void WebPluginDelegateStub::OnImeCompositionCompleted(const string16& text) {
    351   if (delegate_)
    352     delegate_->ImeCompositionCompleted(text);
    353 }
    354 #endif
    355 
    356 #if defined(OS_MACOSX)
    357 void WebPluginDelegateStub::OnSetWindowFocus(bool has_focus) {
    358   if (delegate_)
    359     delegate_->SetWindowHasFocus(has_focus);
    360 }
    361 
    362 void WebPluginDelegateStub::OnContainerHidden() {
    363   if (delegate_)
    364     delegate_->SetContainerVisibility(false);
    365 }
    366 
    367 void WebPluginDelegateStub::OnContainerShown(gfx::Rect window_frame,
    368                                              gfx::Rect view_frame,
    369                                              bool has_focus) {
    370   if (delegate_) {
    371     delegate_->WindowFrameChanged(window_frame, view_frame);
    372     delegate_->SetContainerVisibility(true);
    373     delegate_->SetWindowHasFocus(has_focus);
    374   }
    375 }
    376 
    377 void WebPluginDelegateStub::OnWindowFrameChanged(const gfx::Rect& window_frame,
    378                                                  const gfx::Rect& view_frame) {
    379   if (delegate_)
    380     delegate_->WindowFrameChanged(window_frame, view_frame);
    381 }
    382 
    383 void WebPluginDelegateStub::OnImeCompositionCompleted(const string16& text) {
    384   if (delegate_)
    385     delegate_->ImeCompositionCompleted(text);
    386 }
    387 #endif  // OS_MACOSX
    388 
    389 void WebPluginDelegateStub::OnDidReceiveManualResponse(
    390     const GURL& url,
    391     const PluginMsg_DidReceiveResponseParams& params) {
    392   delegate_->DidReceiveManualResponse(url, params.mime_type, params.headers,
    393                                       params.expected_length,
    394                                       params.last_modified);
    395 }
    396 
    397 void WebPluginDelegateStub::OnDidReceiveManualData(
    398     const std::vector<char>& buffer) {
    399   delegate_->DidReceiveManualData(&buffer.front(),
    400                                   static_cast<int>(buffer.size()));
    401 }
    402 
    403 void WebPluginDelegateStub::OnDidFinishManualLoading() {
    404   delegate_->DidFinishManualLoading();
    405 }
    406 
    407 void WebPluginDelegateStub::OnDidManualLoadFail() {
    408   delegate_->DidManualLoadFail();
    409 }
    410 
    411 void WebPluginDelegateStub::OnHandleURLRequestReply(
    412     unsigned long resource_id, const GURL& url, int notify_id) {
    413   WebPluginResourceClient* resource_client =
    414       delegate_->CreateResourceClient(resource_id, url, notify_id);
    415   webplugin_->OnResourceCreated(resource_id, resource_client);
    416 }
    417 
    418 void WebPluginDelegateStub::OnHTTPRangeRequestReply(
    419     unsigned long resource_id, int range_request_id) {
    420   WebPluginResourceClient* resource_client =
    421       delegate_->CreateSeekableResourceClient(resource_id, range_request_id);
    422   webplugin_->OnResourceCreated(resource_id, resource_client);
    423 }
    424 
    425 }  // namespace content
    426