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