OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2008 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 #define PEPPER_APIS_ENABLED 1 | |
6 | |
7 #include "webkit/glue/plugins/webplugin_delegate_pepper_impl.h" | |
8 | |
9 #include <string> | |
10 #include <vector> | |
11 | |
12 #include "base/file_util.h" | |
13 #include "base/message_loop.h" | |
14 #include "base/process_util.h" | |
15 #include "base/scoped_ptr.h" | |
16 #include "base/stats_counters.h" | |
17 #include "base/string_util.h" | |
18 #include "webkit/api/public/WebInputEvent.h" | |
19 #include "webkit/glue/glue_util.h" | |
20 #include "webkit/glue/plugins/plugin_constants_win.h" | |
21 #include "webkit/glue/plugins/plugin_instance.h" | |
22 #include "webkit/glue/plugins/plugin_lib.h" | |
23 #include "webkit/glue/plugins/plugin_list.h" | |
24 #include "webkit/glue/plugins/plugin_stream_url.h" | |
25 #include "webkit/glue/webkit_glue.h" | |
26 | |
27 using webkit_glue::WebPlugin; | |
28 using webkit_glue::WebPluginDelegate; | |
29 using webkit_glue::WebPluginResourceClient; | |
30 using WebKit::WebCursorInfo; | |
31 using WebKit::WebKeyboardEvent; | |
32 using WebKit::WebInputEvent; | |
33 using WebKit::WebMouseEvent; | |
34 using WebKit::WebMouseWheelEvent; | |
35 | |
36 | |
37 WebPluginDelegatePepperImpl* WebPluginDelegatePepperImpl::Create( | |
38 const FilePath& filename, | |
39 const std::string& mime_type, | |
40 gfx::PluginWindowHandle containing_view) { | |
41 scoped_refptr<NPAPI::PluginLib> plugin_lib = | |
42 NPAPI::PluginLib::CreatePluginLib(filename); | |
43 if (plugin_lib.get() == NULL) | |
44 return NULL; | |
45 | |
46 NPError err = plugin_lib->NP_Initialize(); | |
47 if (err != NPERR_NO_ERROR) | |
48 return NULL; | |
49 | |
50 scoped_refptr<NPAPI::PluginInstance> instance = | |
51 plugin_lib->CreateInstance(mime_type); | |
52 return new WebPluginDelegatePepperImpl(containing_view, instance.get()); | |
53 } | |
54 | |
55 bool WebPluginDelegatePepperImpl::Initialize( | |
56 const GURL& url, | |
57 const std::vector<std::string>& arg_names, | |
58 const std::vector<std::string>& arg_values, | |
59 WebPlugin* plugin, | |
60 bool load_manually) { | |
61 plugin_ = plugin; | |
62 | |
63 instance_->set_web_plugin(plugin_); | |
64 int argc = 0; | |
65 scoped_array<char*> argn(new char*[arg_names.size()]); | |
66 scoped_array<char*> argv(new char*[arg_names.size()]); | |
67 for (size_t i = 0; i < arg_names.size(); ++i) { | |
68 argn[argc] = const_cast<char*>(arg_names[i].c_str()); | |
69 argv[argc] = const_cast<char*>(arg_values[i].c_str()); | |
70 argc++; | |
71 } | |
72 | |
73 bool start_result = instance_->Start( | |
74 url, argn.get(), argv.get(), argc, load_manually); | |
75 if (!start_result) | |
76 return false; | |
77 | |
78 // For windowless plugins we should set the containing window handle | |
79 // as the instance window handle. This is what Safari does. Not having | |
80 // a valid window handle causes subtle bugs with plugins which retreive | |
81 // the window handle and validate the same. The window handle can be | |
82 // retreived via NPN_GetValue of NPNVnetscapeWindow. | |
83 instance_->set_window_handle(parent_); | |
84 | |
85 plugin_url_ = url.spec(); | |
86 | |
87 return true; | |
88 } | |
89 | |
90 void WebPluginDelegatePepperImpl::DestroyInstance() { | |
91 if (instance_ && (instance_->npp()->ndata != NULL)) { | |
92 // Shutdown all streams before destroying so that | |
93 // no streams are left "in progress". Need to do | |
94 // this before calling set_web_plugin(NULL) because the | |
95 // instance uses the helper to do the download. | |
96 instance_->CloseStreams(); | |
97 | |
98 window_.window = NULL; | |
99 instance_->NPP_SetWindow(&window_); | |
100 | |
101 instance_->NPP_Destroy(); | |
102 | |
103 instance_->set_web_plugin(NULL); | |
104 | |
105 instance_ = 0; | |
106 } | |
107 } | |
108 | |
109 void WebPluginDelegatePepperImpl::UpdateGeometry( | |
110 const gfx::Rect& window_rect, | |
111 const gfx::Rect& clip_rect) { | |
112 WindowlessUpdateGeometry(window_rect, clip_rect); | |
113 } | |
114 | |
115 NPObject* WebPluginDelegatePepperImpl::GetPluginScriptableObject() { | |
116 return instance_->GetPluginScriptableObject(); | |
117 } | |
118 | |
119 void WebPluginDelegatePepperImpl::DidFinishLoadWithReason( | |
120 const GURL& url, | |
121 NPReason reason, | |
122 intptr_t notify_data) { | |
123 instance()->DidFinishLoadWithReason( | |
124 url, reason, reinterpret_cast<void*>(notify_data)); | |
125 } | |
126 | |
127 int WebPluginDelegatePepperImpl::GetProcessId() { | |
128 // We are in process, so the plugin pid is this current process pid. | |
129 return base::GetCurrentProcId(); | |
130 } | |
131 | |
132 void WebPluginDelegatePepperImpl::SendJavaScriptStream( | |
133 const GURL& url, | |
134 const std::string& result, | |
135 bool success, | |
136 bool notify_needed, | |
137 intptr_t notify_data) { | |
138 instance()->SendJavaScriptStream(url, result, success, notify_needed, | |
139 notify_data); | |
140 } | |
141 | |
142 void WebPluginDelegatePepperImpl::DidReceiveManualResponse( | |
143 const GURL& url, const std::string& mime_type, | |
144 const std::string& headers, uint32 expected_length, uint32 last_modified) { | |
145 instance()->DidReceiveManualResponse(url, mime_type, headers, | |
146 expected_length, last_modified); | |
147 } | |
148 | |
149 void WebPluginDelegatePepperImpl::DidReceiveManualData(const char* buffer, | |
150 int length) { | |
151 instance()->DidReceiveManualData(buffer, length); | |
152 } | |
153 | |
154 void WebPluginDelegatePepperImpl::DidFinishManualLoading() { | |
155 instance()->DidFinishManualLoading(); | |
156 } | |
157 | |
158 void WebPluginDelegatePepperImpl::DidManualLoadFail() { | |
159 instance()->DidManualLoadFail(); | |
160 } | |
161 | |
162 FilePath WebPluginDelegatePepperImpl::GetPluginPath() { | |
163 return instance()->plugin_lib()->plugin_info().path; | |
164 } | |
165 | |
166 WebPluginResourceClient* WebPluginDelegatePepperImpl::CreateResourceClient( | |
167 int resource_id, const GURL& url, bool notify_needed, | |
168 intptr_t notify_data, intptr_t existing_stream) { | |
169 // Stream already exists. This typically happens for range requests | |
170 // initiated via NPN_RequestRead. | |
171 if (existing_stream) { | |
172 NPAPI::PluginStream* plugin_stream = | |
173 reinterpret_cast<NPAPI::PluginStream*>(existing_stream); | |
174 | |
175 return plugin_stream->AsResourceClient(); | |
176 } | |
177 | |
178 std::string mime_type; | |
179 NPAPI::PluginStreamUrl *stream = instance()->CreateStream( | |
180 resource_id, url, mime_type, notify_needed, | |
181 reinterpret_cast<void*>(notify_data)); | |
182 return stream; | |
183 } | |
184 | |
185 bool WebPluginDelegatePepperImpl::IsPluginDelegateWindow( | |
186 gfx::NativeWindow window) { | |
187 return false; | |
188 } | |
189 | |
190 bool WebPluginDelegatePepperImpl::GetPluginNameFromWindow( | |
191 gfx::NativeWindow window, std::wstring *plugin_name) { | |
192 return false; | |
193 } | |
194 | |
195 bool WebPluginDelegatePepperImpl::IsDummyActivationWindow( | |
196 gfx::NativeWindow window) { | |
197 return false; | |
198 } | |
199 | |
200 WebPluginDelegatePepperImpl::WebPluginDelegatePepperImpl( | |
201 gfx::PluginWindowHandle containing_view, | |
202 NPAPI::PluginInstance *instance) | |
203 : plugin_(NULL), | |
204 instance_(instance), | |
205 parent_(containing_view) { | |
206 memset(&window_, 0, sizeof(window_)); | |
207 } | |
208 | |
209 WebPluginDelegatePepperImpl::~WebPluginDelegatePepperImpl() { | |
210 DestroyInstance(); | |
211 } | |
212 | |
213 void WebPluginDelegatePepperImpl::PluginDestroyed() { | |
214 delete this; | |
215 } | |
216 | |
217 void WebPluginDelegatePepperImpl::Paint(gfx::NativeDrawingContext context, const
gfx::Rect& rect) { | |
218 NOTIMPLEMENTED(); | |
219 } | |
220 | |
221 void WebPluginDelegatePepperImpl::Print(gfx::NativeDrawingContext context) { | |
222 NOTIMPLEMENTED(); | |
223 } | |
224 | |
225 void WebPluginDelegatePepperImpl::InstallMissingPlugin() { | |
226 NOTIMPLEMENTED(); | |
227 } | |
228 | |
229 void WebPluginDelegatePepperImpl::WindowlessUpdateGeometry( | |
230 const gfx::Rect& window_rect, | |
231 const gfx::Rect& clip_rect) { | |
232 // Only resend to the instance if the geometry has changed. | |
233 if (window_rect == window_rect_ && clip_rect == clip_rect_) | |
234 return; | |
235 | |
236 // We will inform the instance of this change when we call NPP_SetWindow. | |
237 clip_rect_ = clip_rect; | |
238 cutout_rects_.clear(); | |
239 | |
240 if (window_rect_ != window_rect) { | |
241 window_rect_ = window_rect; | |
242 WindowlessSetWindow(true); | |
243 // TODO(sehr): update the context here? | |
244 } | |
245 } | |
246 | |
247 void WebPluginDelegatePepperImpl::WindowlessPaint( | |
248 gfx::NativeDrawingContext context, | |
249 const gfx::Rect& damage_rect) { | |
250 static StatsRate plugin_paint("Plugin.Paint"); | |
251 StatsScope<StatsRate> scope(plugin_paint); | |
252 // TODO(sehr): save the context here? | |
253 } | |
254 | |
255 void WebPluginDelegatePepperImpl::WindowlessSetWindow(bool force_set_window) { | |
256 if (!instance()) | |
257 return; | |
258 | |
259 if (window_rect_.IsEmpty()) // wait for geometry to be set. | |
260 return; | |
261 | |
262 window_.clipRect.top = clip_rect_.y(); | |
263 window_.clipRect.left = clip_rect_.x(); | |
264 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); | |
265 window_.clipRect.right = clip_rect_.x() + clip_rect_.width(); | |
266 window_.height = window_rect_.height(); | |
267 window_.width = window_rect_.width(); | |
268 window_.x = window_rect_.x(); | |
269 window_.y = window_rect_.y(); | |
270 window_.type = NPWindowTypeDrawable; | |
271 | |
272 NPError err = instance()->NPP_SetWindow(&window_); | |
273 DCHECK(err == NPERR_NO_ERROR); | |
274 } | |
275 | |
276 void WebPluginDelegatePepperImpl::SetFocus() { | |
277 NPEvent npevent; | |
278 | |
279 npevent.type = NPEventType_Focus; | |
280 npevent.size = sizeof(NPEvent); | |
281 // TODO(sehr): what timestamp should this have? | |
282 npevent.timeStampSeconds = 0.0; | |
283 // Currently this API only supports gaining focus. | |
284 npevent.u.focus.value = 1; | |
285 instance()->NPP_HandleEvent(&npevent); | |
286 } | |
287 | |
288 // Anonymous namespace for functions converting WebInputEvents to NPAPI types. | |
289 namespace { | |
290 NPEventTypes ConvertEventTypes(WebInputEvent::Type wetype) { | |
291 switch (wetype) { | |
292 case WebInputEvent::MouseDown: | |
293 return NPEventType_MouseDown; | |
294 case WebInputEvent::MouseUp: | |
295 return NPEventType_MouseUp; | |
296 case WebInputEvent::MouseMove: | |
297 return NPEventType_MouseMove; | |
298 case WebInputEvent::MouseEnter: | |
299 return NPEventType_MouseEnter; | |
300 case WebInputEvent::MouseLeave: | |
301 return NPEventType_MouseLeave; | |
302 case WebInputEvent::MouseWheel: | |
303 return NPEventType_MouseWheel; | |
304 case WebInputEvent::RawKeyDown: | |
305 return NPEventType_RawKeyDown; | |
306 case WebInputEvent::KeyDown: | |
307 return NPEventType_KeyDown; | |
308 case WebInputEvent::KeyUp: | |
309 return NPEventType_KeyUp; | |
310 case WebInputEvent::Char: | |
311 return NPEventType_Char; | |
312 case WebInputEvent::Undefined: | |
313 default: | |
314 return NPEventType_Undefined; | |
315 } | |
316 } | |
317 | |
318 void BuildKeyEvent(const WebInputEvent* event, NPEvent* npevent) { | |
319 const WebKeyboardEvent* key_event = | |
320 reinterpret_cast<const WebKeyboardEvent*>(event); | |
321 npevent->u.key.modifier = key_event->modifiers; | |
322 npevent->u.key.normalizedKeyCode = key_event->windowsKeyCode; | |
323 } | |
324 | |
325 void BuildCharEvent(const WebInputEvent* event, NPEvent* npevent) { | |
326 const WebKeyboardEvent* key_event = | |
327 reinterpret_cast<const WebKeyboardEvent*>(event); | |
328 npevent->u.character.modifier = key_event->modifiers; | |
329 // For consistency, check that the sizes of the texts agree. | |
330 DCHECK(sizeof(npevent->u.character.text) == sizeof(key_event->text)); | |
331 DCHECK(sizeof(npevent->u.character.unmodifiedText) == | |
332 sizeof(key_event->unmodifiedText)); | |
333 for (size_t i = 0; i < WebKeyboardEvent::textLengthCap; ++i) { | |
334 npevent->u.character.text[i] = key_event->text[i]; | |
335 npevent->u.character.unmodifiedText[i] = key_event->unmodifiedText[i]; | |
336 } | |
337 } | |
338 | |
339 void BuildMouseEvent(const WebInputEvent* event, NPEvent* npevent) { | |
340 const WebMouseEvent* mouse_event = | |
341 reinterpret_cast<const WebMouseEvent*>(event); | |
342 npevent->u.mouse.modifier = mouse_event->modifiers; | |
343 npevent->u.mouse.button = mouse_event->button; | |
344 npevent->u.mouse.x = mouse_event->x; | |
345 npevent->u.mouse.y = mouse_event->y; | |
346 npevent->u.mouse.clickCount = mouse_event->clickCount; | |
347 } | |
348 | |
349 void BuildMouseWheelEvent(const WebInputEvent* event, NPEvent* npevent) { | |
350 const WebMouseWheelEvent* mouse_wheel_event = | |
351 reinterpret_cast<const WebMouseWheelEvent*>(event); | |
352 npevent->u.wheel.modifier = mouse_wheel_event->modifiers; | |
353 npevent->u.wheel.deltaX = mouse_wheel_event->deltaX; | |
354 npevent->u.wheel.deltaY = mouse_wheel_event->deltaY; | |
355 npevent->u.wheel.wheelTicksX = mouse_wheel_event->wheelTicksX; | |
356 npevent->u.wheel.wheelTicksY = mouse_wheel_event->wheelTicksY; | |
357 npevent->u.wheel.scrollByPage = mouse_wheel_event->scrollByPage; | |
358 } | |
359 } // namespace | |
360 | |
361 bool WebPluginDelegatePepperImpl::HandleInputEvent(const WebInputEvent& event, | |
362 WebCursorInfo* cursor_info) { | |
363 NPEvent npevent; | |
364 | |
365 npevent.type = ConvertEventTypes(event.type); | |
366 npevent.size = sizeof(NPEvent); | |
367 npevent.timeStampSeconds = event.timeStampSeconds; | |
368 switch (npevent.type) { | |
369 case NPEventType_Undefined: | |
370 return false; | |
371 case NPEventType_MouseDown: | |
372 case NPEventType_MouseUp: | |
373 case NPEventType_MouseMove: | |
374 case NPEventType_MouseEnter: | |
375 case NPEventType_MouseLeave: | |
376 BuildMouseEvent(&event, &npevent); | |
377 break; | |
378 case NPEventType_MouseWheel: | |
379 BuildMouseWheelEvent(&event, &npevent); | |
380 break; | |
381 case NPEventType_RawKeyDown: | |
382 case NPEventType_KeyDown: | |
383 case NPEventType_KeyUp: | |
384 BuildKeyEvent(&event, &npevent); | |
385 case NPEventType_Char: | |
386 BuildCharEvent(&event, &npevent); | |
387 break; | |
388 case NPEventType_Minimize: | |
389 case NPEventType_Focus: | |
390 case NPEventType_Device: | |
391 NOTIMPLEMENTED(); | |
392 break; | |
393 } | |
394 return instance()->NPP_HandleEvent(&npevent) != 0; | |
395 } | |
OLD | NEW |