Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / child / npapi / webplugin_delegate_impl.cc
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_frame_id,
320                                      int render_view_id) {
321   // TODO(jam): once we switch over to resource loading always happening in this
322   // code path, remove WebPluginResourceClient abstraction.
323   PluginStreamUrl* plugin_stream = instance()->CreateStream(
324       resource_id, url, std::string(), notify_id);
325
326   bool copy_stream_data = !!(quirks_ & PLUGIN_QUIRK_COPY_STREAM_DATA);
327   plugin_stream->SetPluginURLFetcher(new PluginURLFetcher(
328       plugin_stream, url, first_party_for_cookies, method, buf, len,
329       referrer, notify_redirects, is_plugin_src_load, origin_pid,
330       render_frame_id, render_view_id, resource_id, copy_stream_data));
331 }
332
333 }  // namespace content