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