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/child/npapi/webplugin_delegate_impl.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/process/process_handle.h"
     13 #include "base/strings/string_util.h"
     14 #include "content/child/npapi/plugin_instance.h"
     15 #include "content/child/npapi/plugin_lib.h"
     16 #include "content/child/npapi/plugin_stream_url.h"
     17 #include "third_party/WebKit/public/web/WebInputEvent.h"
     18 #include "webkit/glue/webkit_glue.h"
     19 
     20 using WebKit::WebCursorInfo;
     21 using WebKit::WebInputEvent;
     22 
     23 namespace content {
     24 
     25 WebPluginDelegateImpl* WebPluginDelegateImpl::Create(
     26     const base::FilePath& filename,
     27     const std::string& mime_type) {
     28   scoped_refptr<PluginLib> plugin_lib(PluginLib::CreatePluginLib(filename));
     29   if (plugin_lib.get() == NULL)
     30     return NULL;
     31 
     32   NPError err = plugin_lib->NP_Initialize();
     33   if (err != NPERR_NO_ERROR)
     34     return NULL;
     35 
     36   scoped_refptr<PluginInstance> instance(plugin_lib->CreateInstance(mime_type));
     37   return new WebPluginDelegateImpl(instance.get());
     38 }
     39 
     40 void WebPluginDelegateImpl::PluginDestroyed() {
     41   if (handle_event_depth_) {
     42     base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
     43   } else {
     44     delete this;
     45   }
     46 }
     47 
     48 bool WebPluginDelegateImpl::Initialize(
     49     const GURL& url,
     50     const std::vector<std::string>& arg_names,
     51     const std::vector<std::string>& arg_values,
     52     WebPlugin* plugin,
     53     bool load_manually) {
     54   plugin_ = plugin;
     55 
     56   instance_->set_web_plugin(plugin_);
     57   if (quirks_ & PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES) {
     58     PluginLib* plugin_lib = instance()->plugin_lib();
     59     if (plugin_lib->instance_count() > 1) {
     60       return false;
     61     }
     62   }
     63 
     64   int argc = 0;
     65   scoped_ptr<char*[]> argn(new char*[arg_names.size()]);
     66   scoped_ptr<char*[]> argv(new char*[arg_names.size()]);
     67   for (size_t i = 0; i < arg_names.size(); ++i) {
     68     if (quirks_ & PLUGIN_QUIRK_NO_WINDOWLESS &&
     69         LowerCaseEqualsASCII(arg_names[i], "windowlessvideo")) {
     70       continue;
     71     }
     72     argn[argc] = const_cast<char*>(arg_names[i].c_str());
     73     argv[argc] = const_cast<char*>(arg_values[i].c_str());
     74     argc++;
     75   }
     76 
     77   creation_succeeded_ = instance_->Start(
     78       url, argn.get(), argv.get(), argc, load_manually);
     79   if (!creation_succeeded_) {
     80     VLOG(1) << "Couldn't start plug-in instance";
     81     return false;
     82   }
     83 
     84   windowless_ = instance_->windowless();
     85   if (!windowless_) {
     86     if (!WindowedCreatePlugin()) {
     87       VLOG(1) << "Couldn't create windowed plug-in";
     88       return false;
     89     }
     90   }
     91 
     92   bool should_load = PlatformInitialize();
     93 
     94   plugin_url_ = url.spec();
     95 
     96   return should_load;
     97 }
     98 
     99 void WebPluginDelegateImpl::DestroyInstance() {
    100   if (instance_.get() && (instance_->npp()->ndata != NULL)) {
    101     // Shutdown all streams before destroying so that
    102     // no streams are left "in progress".  Need to do
    103     // this before calling set_web_plugin(NULL) because the
    104     // instance uses the helper to do the download.
    105     instance_->CloseStreams();
    106 
    107     window_.window = NULL;
    108     if (creation_succeeded_ &&
    109         !(quirks_ & PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY)) {
    110       instance_->NPP_SetWindow(&window_);
    111     }
    112 
    113     instance_->NPP_Destroy();
    114 
    115     instance_->set_web_plugin(NULL);
    116 
    117     PlatformDestroyInstance();
    118 
    119     instance_ = 0;
    120   }
    121 }
    122 
    123 void WebPluginDelegateImpl::UpdateGeometry(
    124     const gfx::Rect& window_rect,
    125     const gfx::Rect& clip_rect) {
    126 
    127   if (first_set_window_call_) {
    128     first_set_window_call_ = false;
    129     // Plugins like media player on Windows have a bug where in they handle the
    130     // first geometry update and ignore the rest resulting in painting issues.
    131     // This quirk basically ignores the first set window call sequence for
    132     // these plugins and has been tested for Windows plugins only.
    133     if (quirks_ & PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL)
    134       return;
    135   }
    136 
    137   if (windowless_) {
    138     WindowlessUpdateGeometry(window_rect, clip_rect);
    139   } else {
    140     WindowedUpdateGeometry(window_rect, clip_rect);
    141   }
    142 }
    143 
    144 void WebPluginDelegateImpl::SetFocus(bool focused) {
    145   DCHECK(windowless_);
    146   // This is called when internal WebKit focus (the focused element on the page)
    147   // changes, but plugins need to know about OS-level focus, so we have an extra
    148   // layer of focus tracking.
    149   //
    150   // On Windows, historically browsers did not set focus events to windowless
    151   // plugins when the toplevel window focus changes. Sending such focus events
    152   // breaks full screen mode in Flash because it will come out of full screen
    153   // mode when it loses focus, and its full screen window causes the browser to
    154   // lose focus.
    155   has_webkit_focus_ = focused;
    156 #if !defined(OS_WIN)
    157   if (containing_view_has_focus_)
    158     SetPluginHasFocus(focused);
    159 #else
    160   SetPluginHasFocus(focused);
    161 #endif
    162 }
    163 
    164 void WebPluginDelegateImpl::SetPluginHasFocus(bool focused) {
    165   if (focused == plugin_has_focus_)
    166     return;
    167   if (PlatformSetPluginHasFocus(focused))
    168     plugin_has_focus_ = focused;
    169 }
    170 
    171 void WebPluginDelegateImpl::SetContentAreaHasFocus(bool has_focus) {
    172   containing_view_has_focus_ = has_focus;
    173   if (!windowless_)
    174     return;
    175 #if !defined(OS_WIN)  // See SetFocus above.
    176   SetPluginHasFocus(containing_view_has_focus_ && has_webkit_focus_);
    177 #endif
    178 }
    179 
    180 NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() {
    181   return instance_->GetPluginScriptableObject();
    182 }
    183 
    184 NPP WebPluginDelegateImpl::GetPluginNPP() {
    185   return instance_->npp();
    186 }
    187 
    188 bool WebPluginDelegateImpl::GetFormValue(base::string16* value) {
    189   return instance_->GetFormValue(value);
    190 }
    191 
    192 void WebPluginDelegateImpl::DidFinishLoadWithReason(const GURL& url,
    193                                                     NPReason reason,
    194                                                     int notify_id) {
    195   if (quirks_ & PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS &&
    196       reason == NPRES_NETWORK_ERR) {
    197     // Flash needs this or otherwise it unloads the launching swf object.
    198     reason = NPRES_DONE;
    199   }
    200 
    201   instance()->DidFinishLoadWithReason(url, reason, notify_id);
    202 }
    203 
    204 int WebPluginDelegateImpl::GetProcessId() {
    205   // We are in process, so the plugin pid is this current process pid.
    206   return base::GetCurrentProcId();
    207 }
    208 
    209 void WebPluginDelegateImpl::SendJavaScriptStream(const GURL& url,
    210                                                  const std::string& result,
    211                                                  bool success,
    212                                                  int notify_id) {
    213   instance()->SendJavaScriptStream(url, result, success, notify_id);
    214 }
    215 
    216 void WebPluginDelegateImpl::DidReceiveManualResponse(
    217     const GURL& url, const std::string& mime_type,
    218     const std::string& headers, uint32 expected_length, uint32 last_modified) {
    219   if (!windowless_) {
    220     // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in
    221     // Flash.  See http://b/issue?id=892174.
    222     DCHECK(windowed_did_set_window_);
    223   }
    224 
    225   instance()->DidReceiveManualResponse(url, mime_type, headers,
    226                                        expected_length, last_modified);
    227 }
    228 
    229 void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer,
    230                                                  int length) {
    231   instance()->DidReceiveManualData(buffer, length);
    232 }
    233 
    234 void WebPluginDelegateImpl::DidFinishManualLoading() {
    235   instance()->DidFinishManualLoading();
    236 }
    237 
    238 void WebPluginDelegateImpl::DidManualLoadFail() {
    239   instance()->DidManualLoadFail();
    240 }
    241 
    242 base::FilePath WebPluginDelegateImpl::GetPluginPath() {
    243   return instance()->plugin_lib()->plugin_info().path;
    244 }
    245 
    246 void WebPluginDelegateImpl::WindowedUpdateGeometry(
    247     const gfx::Rect& window_rect,
    248     const gfx::Rect& clip_rect) {
    249   if (WindowedReposition(window_rect, clip_rect) ||
    250       !windowed_did_set_window_) {
    251     // Let the plugin know that it has been moved
    252     WindowedSetWindow();
    253   }
    254 }
    255 
    256 bool WebPluginDelegateImpl::HandleInputEvent(
    257     const WebInputEvent& event,
    258     WebCursor::CursorInfo* cursor_info) {
    259   DCHECK(windowless_) << "events should only be received in windowless mode";
    260 
    261   bool pop_user_gesture = false;
    262   if (IsUserGesture(event)) {
    263     pop_user_gesture = true;
    264     instance()->PushPopupsEnabledState(true);
    265   }
    266 
    267   bool handled = PlatformHandleInputEvent(event, cursor_info);
    268 
    269   if (pop_user_gesture) {
    270     instance()->PopPopupsEnabledState();
    271   }
    272 
    273   return handled;
    274 }
    275 
    276 bool WebPluginDelegateImpl::IsUserGesture(const WebInputEvent& event) {
    277   switch (event.type) {
    278     case WebInputEvent::MouseDown:
    279     case WebInputEvent::MouseUp:
    280     case WebInputEvent::KeyDown:
    281     case WebInputEvent::KeyUp:
    282       return true;
    283     default:
    284       return false;
    285   }
    286   return false;
    287 }
    288 
    289 WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(
    290     unsigned long resource_id, const GURL& url, int notify_id) {
    291   return instance()->CreateStream(
    292       resource_id, url, std::string(), notify_id);
    293 }
    294 
    295 WebPluginResourceClient* WebPluginDelegateImpl::CreateSeekableResourceClient(
    296     unsigned long resource_id, int range_request_id) {
    297   WebPluginResourceClient* resource_client = instance()->GetRangeRequest(
    298       range_request_id);
    299   if (resource_client)
    300     resource_client->AddRangeRequestResourceId(resource_id);
    301   return resource_client;
    302 }
    303 
    304 }  // namespace content
    305