| 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 |