Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / child / npapi / webplugin_delegate_impl.cc
blob9d760549acf3ac13f56cffc1343155fd5b2fe65f
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.
5 #include "content/child/npapi/webplugin_delegate_impl.h"
7 #include <string>
8 #include <vector>
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"
21 using blink::WebCursorInfo;
22 using blink::WebInputEvent;
24 namespace content {
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;
34 NPError err = plugin_lib->NP_Initialize();
35 if (err != NPERR_NO_ERROR)
36 return NULL;
38 scoped_refptr<PluginInstance> instance(plugin_lib->CreateInstance(mime_type));
39 return new WebPluginDelegateImpl(plugin, instance.get());
42 void WebPluginDelegateImpl::PluginDestroyed() {
43 if (handle_event_depth_) {
44 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
45 } else {
46 delete this;
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;
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;
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;
76 argn[argc] = const_cast<char*>(arg_names[i].c_str());
77 argv[argc] = const_cast<char*>(arg_values[i].c_str());
78 argc++;
81 creation_succeeded_ = instance_->Start(
82 url, argn.get(), argv.get(), argc, load_manually);
83 if (!creation_succeeded_) {
84 VLOG(1) << "Couldn't start plugin instance";
85 return false;
88 windowless_ = instance_->windowless();
89 if (!windowless_) {
90 if (!WindowedCreatePlugin()) {
91 VLOG(1) << "Couldn't create windowed plugin";
92 return false;
96 bool should_load = PlatformInitialize();
98 plugin_url_ = url.spec();
100 return should_load;
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();
111 window_.window = NULL;
112 if (creation_succeeded_ &&
113 !(quirks_ & PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY)) {
114 instance_->NPP_SetWindow(&window_);
117 instance_->NPP_Destroy();
119 instance_->set_web_plugin(NULL);
121 PlatformDestroyInstance();
123 instance_ = 0;
127 void WebPluginDelegateImpl::UpdateGeometry(
128 const gfx::Rect& window_rect,
129 const gfx::Rect& clip_rect) {
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;
141 if (windowless_) {
142 WindowlessUpdateGeometry(window_rect, clip_rect);
143 } else {
144 WindowedUpdateGeometry(window_rect, clip_rect);
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.
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
168 void WebPluginDelegateImpl::SetPluginHasFocus(bool focused) {
169 if (focused == plugin_has_focus_)
170 return;
171 if (PlatformSetPluginHasFocus(focused))
172 plugin_has_focus_ = focused;
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
184 NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() {
185 return instance_->GetPluginScriptableObject();
188 NPP WebPluginDelegateImpl::GetPluginNPP() {
189 return instance_->npp();
192 bool WebPluginDelegateImpl::GetFormValue(base::string16* value) {
193 return instance_->GetFormValue(value);
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;
205 instance()->DidFinishLoadWithReason(url, reason, notify_id);
208 int WebPluginDelegateImpl::GetProcessId() {
209 // We are in process, so the plugin pid is this current process pid.
210 return base::GetCurrentProcId();
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);
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_);
229 instance()->DidReceiveManualResponse(url, mime_type, headers,
230 expected_length, last_modified);
233 void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer,
234 int length) {
235 instance()->DidReceiveManualData(buffer, length);
238 void WebPluginDelegateImpl::DidFinishManualLoading() {
239 instance()->DidFinishManualLoading();
242 void WebPluginDelegateImpl::DidManualLoadFail() {
243 instance()->DidManualLoadFail();
246 base::FilePath WebPluginDelegateImpl::GetPluginPath() {
247 return instance()->plugin_lib()->plugin_info().path;
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();
260 bool WebPluginDelegateImpl::HandleInputEvent(
261 const WebInputEvent& event,
262 WebCursor::CursorInfo* cursor_info) {
263 DCHECK(windowless_) << "events should only be received in windowless mode";
265 bool pop_user_gesture = false;
266 if (IsUserGesture(event)) {
267 pop_user_gesture = true;
268 instance()->PushPopupsEnabledState(true);
271 bool handled = PlatformHandleInputEvent(event, cursor_info);
273 if (pop_user_gesture) {
274 instance()->PopPopupsEnabledState();
277 return handled;
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;
292 WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(
293 unsigned long resource_id, const GURL& url, int notify_id) {
294 return instance()->CreateStream(
295 resource_id, url, std::string(), notify_id);
298 WebPluginResourceClient* WebPluginDelegateImpl::CreateSeekableResourceClient(
299 unsigned long resource_id, int range_request_id) {
300 WebPluginResourceClient* resource_client = instance()->GetRangeRequest(
301 range_request_id);
302 if (resource_client)
303 resource_client->AddRangeRequestResourceId(resource_id);
304 return resource_client;
307 void WebPluginDelegateImpl::FetchURL(unsigned long resource_id,
308 int notify_id,
309 const GURL& url,
310 const GURL& first_party_for_cookies,
311 const std::string& method,
312 const char* buf,
313 unsigned int len,
314 const Referrer& referrer,
315 bool notify_redirects,
316 bool is_plugin_src_load,
317 int origin_pid,
318 int render_frame_id,
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);
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, std::string(), notify_redirects, is_plugin_src_load, origin_pid,
329 render_frame_id, render_view_id, resource_id, copy_stream_data));
332 } // namespace content