| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import <Cocoa/Cocoa.h> |
| 6 |
| 5 #include "config.h" | 7 #include "config.h" |
| 6 #include "webkit/glue/plugins/webplugin_delegate_impl.h" | 8 #include "webkit/glue/plugins/webplugin_delegate_impl.h" |
| 7 | 9 |
| 8 #include <string> | 10 #include <string> |
| 9 #include <vector> | 11 #include <vector> |
| 10 | 12 |
| 11 #include "base/file_util.h" | 13 #include "base/file_util.h" |
| 12 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
| 13 #include "base/message_loop.h" | 15 #include "base/message_loop.h" |
| 14 #include "base/stats_counters.h" | 16 #include "base/stats_counters.h" |
| 15 #include "base/string_util.h" | 17 #include "base/string_util.h" |
| 16 #include "webkit/api/public/WebInputEvent.h" | 18 #include "webkit/api/public/WebInputEvent.h" |
| 17 #include "webkit/default_plugin/plugin_impl.h" | 19 #include "webkit/default_plugin/plugin_impl.h" |
| 18 #include "webkit/glue/glue_util.h" | 20 #include "webkit/glue/glue_util.h" |
| 19 #include "webkit/glue/webplugin.h" | 21 #include "webkit/glue/webplugin.h" |
| 20 #include "webkit/glue/plugins/plugin_constants_win.h" | 22 #include "webkit/glue/plugins/plugin_constants_win.h" |
| 21 #include "webkit/glue/plugins/plugin_instance.h" | 23 #include "webkit/glue/plugins/plugin_instance.h" |
| 22 #include "webkit/glue/plugins/plugin_lib.h" | 24 #include "webkit/glue/plugins/plugin_lib.h" |
| 23 #include "webkit/glue/plugins/plugin_list.h" | 25 #include "webkit/glue/plugins/plugin_list.h" |
| 24 #include "webkit/glue/plugins/plugin_stream_url.h" | 26 #include "webkit/glue/plugins/plugin_stream_url.h" |
| 25 #include "webkit/glue/webkit_glue.h" | 27 #include "webkit/glue/webkit_glue.h" |
| 26 | 28 |
| 27 using WebKit::WebCursorInfo; | 29 using WebKit::WebCursorInfo; |
| 28 using WebKit::WebKeyboardEvent; | 30 using WebKit::WebKeyboardEvent; |
| 29 using WebKit::WebInputEvent; | 31 using WebKit::WebInputEvent; |
| 30 using WebKit::WebMouseEvent; | 32 using WebKit::WebMouseEvent; |
| 31 | 33 |
| 34 // Important implementation notes: The Mac definition of NPAPI, particularly |
| 35 // the distinction between windowed and windowless modes, differs from the |
| 36 // Windows and Linux definitions. Most of those differences are |
| 37 // accomodated by the WebPluginDelegate class. |
| 38 |
| 32 namespace { | 39 namespace { |
| 33 | 40 |
| 34 const wchar_t kWebPluginDelegateProperty[] = L"WebPluginDelegateProperty"; | 41 // The fastest we are willing to process idle events for Flash. |
| 35 const wchar_t kPluginNameAtomProperty[] = L"PluginNameAtom"; | |
| 36 const wchar_t kDummyActivationWindowName[] = L"DummyWindowForActivation"; | |
| 37 const wchar_t kPluginOrigProc[] = L"OriginalPtr"; | |
| 38 const wchar_t kPluginFlashThrottle[] = L"FlashThrottle"; | |
| 39 | |
| 40 // The fastest we are willing to process WM_USER+1 events for Flash. | |
| 41 // Flash can easily exceed the limits of our CPU if we don't throttle it. | 42 // Flash can easily exceed the limits of our CPU if we don't throttle it. |
| 42 // The throttle has been chosen by testing various delays and compromising | 43 // The throttle has been chosen by testing various delays and compromising |
| 43 // on acceptable Flash performance and reasonable CPU consumption. | 44 // on acceptable Flash performance and reasonable CPU consumption. |
| 44 // | 45 // |
| 45 // I'd like to make the throttle delay variable, based on the amount of | 46 // We'd like to make the throttle delay variable, based on the amount of |
| 46 // time currently required to paint Flash plugins. There isn't a good | 47 // time currently required to paint Flash plugins. There isn't a good |
| 47 // way to count the time spent in aggregate plugin painting, however, so | 48 // way to count the time spent in aggregate plugin painting, however, so |
| 48 // this seems to work well enough. | 49 // this seems to work well enough. |
| 49 const int kFlashWMUSERMessageThrottleDelayMs = 5; | 50 const int kFlashIdleThrottleDelayMs = 20; // 20ms (50Hz) |
| 50 | 51 |
| 51 // The current instance of the plugin which entered the modal loop. | 52 // The current instance of the plugin which entered the modal loop. |
| 52 WebPluginDelegateImpl* g_current_plugin_instance = NULL; | 53 WebPluginDelegateImpl* g_current_plugin_instance = NULL; |
| 53 | 54 |
| 54 // base::LazyInstance<std::list<MSG> > g_throttle_queue(base::LINKER_INITIALIZED
); | |
| 55 | |
| 56 | |
| 57 } // namespace | 55 } // namespace |
| 58 | 56 |
| 59 WebPluginDelegate* WebPluginDelegate::Create( | 57 WebPluginDelegate* WebPluginDelegate::Create( |
| 60 const FilePath& filename, | 58 const FilePath& filename, |
| 61 const std::string& mime_type, | 59 const std::string& mime_type, |
| 62 gfx::PluginWindowHandle containing_view) { | 60 gfx::PluginWindowHandle containing_view) { |
| 63 scoped_refptr<NPAPI::PluginLib> plugin = | 61 scoped_refptr<NPAPI::PluginLib> plugin = |
| 64 NPAPI::PluginLib::CreatePluginLib(filename); | 62 NPAPI::PluginLib::CreatePluginLib(filename); |
| 65 if (plugin.get() == NULL) | 63 if (plugin.get() == NULL) |
| 66 return NULL; | 64 return NULL; |
| 67 | 65 |
| 68 NPError err = plugin->NP_Initialize(); | 66 NPError err = plugin->NP_Initialize(); |
| 69 if (err != NPERR_NO_ERROR) | 67 if (err != NPERR_NO_ERROR) |
| 70 return NULL; | 68 return NULL; |
| 71 | 69 |
| 72 scoped_refptr<NPAPI::PluginInstance> instance = | 70 scoped_refptr<NPAPI::PluginInstance> instance = |
| 73 plugin->CreateInstance(mime_type); | 71 plugin->CreateInstance(mime_type); |
| 74 return new WebPluginDelegateImpl(containing_view, instance.get()); | 72 return new WebPluginDelegateImpl(containing_view, instance.get()); |
| 75 } | 73 } |
| 76 | 74 |
| 77 WebPluginDelegateImpl::WebPluginDelegateImpl( | 75 WebPluginDelegateImpl::WebPluginDelegateImpl( |
| 78 gfx::PluginWindowHandle containing_view, | 76 gfx::PluginWindowHandle containing_view, |
| 79 NPAPI::PluginInstance *instance) | 77 NPAPI::PluginInstance *instance) |
| 80 : parent_(containing_view), | 78 : parent_(containing_view), |
| 81 instance_(instance), | 79 instance_(instance), |
| 82 quirks_(0), | 80 quirks_(0), |
| 83 plugin_(NULL), | 81 plugin_(NULL), |
| 84 windowless_(false), | 82 // all Mac plugins are "windowless" in the Windows/X11 sense |
| 85 windowed_handle_(NULL), | 83 windowless_(true), |
| 86 windowed_did_set_window_(false), | |
| 87 windowless_needs_set_window_(true), | 84 windowless_needs_set_window_(true), |
| 88 handle_event_depth_(0), | 85 handle_event_depth_(0), |
| 89 user_gesture_message_posted_(this), | 86 user_gesture_message_posted_(this), |
| 90 user_gesture_msg_factory_(this) { | 87 user_gesture_msg_factory_(this) { |
| 91 memset(&window_, 0, sizeof(window_)); | 88 memset(&window_, 0, sizeof(window_)); |
| 92 | |
| 93 const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info(); | |
| 94 std::string filename = | |
| 95 StringToLowerASCII(plugin_info.path.BaseName().value()); | |
| 96 | |
| 97 // plugin_module_handle_ = ::GetModuleHandle(plugin_info.path.value().c_str())
; | |
| 98 } | 89 } |
| 99 | 90 |
| 100 WebPluginDelegateImpl::~WebPluginDelegateImpl() { | 91 WebPluginDelegateImpl::~WebPluginDelegateImpl() { |
| 101 DestroyInstance(); | 92 DestroyInstance(); |
| 102 | 93 |
| 103 if (!windowless_) | 94 if (cg_context_.window) |
| 104 WindowedDestroyWindow(); | 95 DisposeWindow(cg_context_.window); |
| 105 } | 96 } |
| 106 | 97 |
| 107 void WebPluginDelegateImpl::PluginDestroyed() { | 98 void WebPluginDelegateImpl::PluginDestroyed() { |
| 108 delete this; | 99 delete this; |
| 109 } | 100 } |
| 110 | 101 |
| 111 bool WebPluginDelegateImpl::Initialize(const GURL& url, | 102 bool WebPluginDelegateImpl::Initialize(const GURL& url, |
| 112 char** argn, | 103 char** argn, |
| 113 char** argv, | 104 char** argv, |
| 114 int argc, | 105 int argc, |
| 115 WebPlugin* plugin, | 106 WebPlugin* plugin, |
| 116 bool load_manually) { | 107 bool load_manually) { |
| 117 plugin_ = plugin; | 108 plugin_ = plugin; |
| 118 | 109 |
| 119 instance_->set_web_plugin(plugin); | 110 instance_->set_web_plugin(plugin); |
| 120 NPAPI::PluginInstance* old_instance = | 111 NPAPI::PluginInstance* old_instance = |
| 121 NPAPI::PluginInstance::SetInitializingInstance(instance_); | 112 NPAPI::PluginInstance::SetInitializingInstance(instance_); |
| 122 | 113 |
| 123 | 114 |
| 124 bool start_result = instance_->Start(url, argn, argv, argc, load_manually); | 115 bool start_result = instance_->Start(url, argn, argv, argc, load_manually); |
| 125 | 116 |
| 126 NPAPI::PluginInstance::SetInitializingInstance(old_instance); | 117 NPAPI::PluginInstance::SetInitializingInstance(old_instance); |
| 127 | 118 |
| 128 if (!start_result) | 119 if (!start_result) |
| 129 return false; | 120 return false; |
| 130 | 121 |
| 131 windowless_ = instance_->windowless(); | 122 cg_context_.window = NULL; |
| 132 if (windowless_) { | 123 window_.window = &cg_context_; |
| 133 // For windowless plugins we should set the containing window handle | 124 window_.type = NPWindowTypeDrawable; |
| 134 // as the instance window handle. This is what Safari does. Not having | |
| 135 // a valid window handle causes subtle bugs with plugins which retreive | |
| 136 // the window handle and validate the same. The window handle can be | |
| 137 // retreived via NPN_GetValue of NPNVnetscapeWindow. | |
| 138 // instance_->set_window_handle(parent_); | |
| 139 } else { | |
| 140 if (!WindowedCreatePlugin()) | |
| 141 return false; | |
| 142 } | |
| 143 | 125 |
| 144 // plugin->SetWindow(windowed_handle_); | 126 plugin->SetWindow(NULL); |
| 145 plugin_url_ = url.spec(); | 127 plugin_url_ = url.spec(); |
| 146 | 128 |
| 147 return true; | 129 return true; |
| 148 } | 130 } |
| 149 | 131 |
| 150 void WebPluginDelegateImpl::DestroyInstance() { | 132 void WebPluginDelegateImpl::DestroyInstance() { |
| 151 if (instance_ && (instance_->npp()->ndata != NULL)) { | 133 if (instance_ && (instance_->npp()->ndata != NULL)) { |
| 152 // Shutdown all streams before destroying so that | 134 // Shutdown all streams before destroying so that |
| 153 // no streams are left "in progress". Need to do | 135 // no streams are left "in progress". Need to do |
| 154 // this before calling set_web_plugin(NULL) because the | 136 // this before calling set_web_plugin(NULL) because the |
| 155 // instance uses the helper to do the download. | 137 // instance uses the helper to do the download. |
| 156 instance_->CloseStreams(); | 138 instance_->CloseStreams(); |
| 157 | |
| 158 window_.window = NULL; | |
| 159 instance_->NPP_SetWindow(&window_); | |
| 160 | |
| 161 instance_->NPP_Destroy(); | 139 instance_->NPP_Destroy(); |
| 162 | |
| 163 instance_->set_web_plugin(NULL); | 140 instance_->set_web_plugin(NULL); |
| 164 | |
| 165 if (instance_->plugin_lib()) { | |
| 166 // Unpatch if this is the last plugin instance. | |
| 167 } | |
| 168 | |
| 169 instance_ = 0; | 141 instance_ = 0; |
| 170 } | 142 } |
| 171 } | 143 } |
| 172 | 144 |
| 173 void WebPluginDelegateImpl::UpdateGeometry( | 145 void WebPluginDelegateImpl::UpdateGeometry( |
| 174 const gfx::Rect& window_rect, | 146 const gfx::Rect& window_rect, |
| 175 const gfx::Rect& clip_rect) { | 147 const gfx::Rect& clip_rect) { |
| 176 if (windowless_) { | 148 |
| 177 WindowlessUpdateGeometry(window_rect, clip_rect); | 149 if (!window_rect.IsEmpty()) { |
| 178 } else { | 150 NSPoint windowOffset = {0.0, 0.0}; |
| 179 WindowedUpdateGeometry(window_rect, clip_rect); | 151 Rect window_bounds; |
| 152 window_bounds.top = window_rect.y() + windowOffset.y; |
| 153 window_bounds.left = window_rect.x() + windowOffset.x; |
| 154 window_bounds.bottom = window_rect.y() + window_rect.height(); |
| 155 window_bounds.right = window_rect.x() + window_rect.width(); |
| 156 |
| 157 if (!cg_context_.window) { |
| 158 // For all plugins we create a placeholder offscreen window for the use |
| 159 // of NPWindow. NPAPI on the Mac requires a Carbon WindowRef for the |
| 160 // "browser window", even if we're not using the Quickdraw drawing model. |
| 161 // Not having a valid window reference causes subtle bugs with plugins |
| 162 // which retreive the NPWindow and validate the same. The NPWindow |
| 163 // can be retreived via NPN_GetValue of NPNVnetscapeWindow. |
| 164 |
| 165 WindowRef window_ref; |
| 166 if (CreateNewWindow(kDocumentWindowClass, |
| 167 kWindowStandardDocumentAttributes, |
| 168 &window_bounds, |
| 169 &window_ref) == noErr) { |
| 170 cg_context_.window = window_ref; |
| 171 } |
| 172 } else { |
| 173 SetWindowBounds(cg_context_.window, kWindowContentRgn, &window_bounds); |
| 174 } |
| 180 } | 175 } |
| 176 |
| 177 WindowlessUpdateGeometry(window_rect, clip_rect); |
| 181 } | 178 } |
| 182 | 179 |
| 183 void WebPluginDelegateImpl::Paint(CGContextRef context, const gfx::Rect& rect) { | 180 void WebPluginDelegateImpl::Paint(CGContextRef context, const gfx::Rect& rect) { |
| 184 if (windowless_) | 181 if (windowless_) |
| 185 WindowlessPaint(context, rect); | 182 WindowlessPaint(context, rect); |
| 186 } | 183 } |
| 187 | 184 |
| 188 void WebPluginDelegateImpl::Print(CGContextRef context) { | 185 void WebPluginDelegateImpl::Print(CGContextRef context) { |
| 189 // Disabling the call to NPP_Print as it causes a crash in | 186 // Disabling the call to NPP_Print as it causes a crash in |
| 190 // flash in some cases. In any case this does not work as expected | 187 // flash in some cases. In any case this does not work as expected |
| (...skipping 20 matching lines...) Expand all Loading... |
| 211 bool success, | 208 bool success, |
| 212 bool notify_needed, | 209 bool notify_needed, |
| 213 intptr_t notify_data) { | 210 intptr_t notify_data) { |
| 214 instance()->SendJavaScriptStream(url, result, success, notify_needed, | 211 instance()->SendJavaScriptStream(url, result, success, notify_needed, |
| 215 notify_data); | 212 notify_data); |
| 216 } | 213 } |
| 217 | 214 |
| 218 void WebPluginDelegateImpl::DidReceiveManualResponse( | 215 void WebPluginDelegateImpl::DidReceiveManualResponse( |
| 219 const std::string& url, const std::string& mime_type, | 216 const std::string& url, const std::string& mime_type, |
| 220 const std::string& headers, uint32 expected_length, uint32 last_modified) { | 217 const std::string& headers, uint32 expected_length, uint32 last_modified) { |
| 221 if (!windowless_) { | |
| 222 // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in | |
| 223 // Flash. See http://b/issue?id=892174. | |
| 224 DCHECK(windowed_did_set_window_); | |
| 225 } | |
| 226 | |
| 227 instance()->DidReceiveManualResponse(url, mime_type, headers, | 218 instance()->DidReceiveManualResponse(url, mime_type, headers, |
| 228 expected_length, last_modified); | 219 expected_length, last_modified); |
| 229 } | 220 } |
| 230 | 221 |
| 231 void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer, | 222 void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer, |
| 232 int length) { | 223 int length) { |
| 233 instance()->DidReceiveManualData(buffer, length); | 224 instance()->DidReceiveManualData(buffer, length); |
| 234 } | 225 } |
| 235 | 226 |
| 236 void WebPluginDelegateImpl::DidFinishManualLoading() { | 227 void WebPluginDelegateImpl::DidFinishManualLoading() { |
| 237 instance()->DidFinishManualLoading(); | 228 instance()->DidFinishManualLoading(); |
| 238 } | 229 } |
| 239 | 230 |
| 240 void WebPluginDelegateImpl::DidManualLoadFail() { | 231 void WebPluginDelegateImpl::DidManualLoadFail() { |
| 241 instance()->DidManualLoadFail(); | 232 instance()->DidManualLoadFail(); |
| 242 } | 233 } |
| 243 | 234 |
| 244 FilePath WebPluginDelegateImpl::GetPluginPath() { | 235 FilePath WebPluginDelegateImpl::GetPluginPath() { |
| 245 return instance()->plugin_lib()->plugin_info().path; | 236 return instance()->plugin_lib()->plugin_info().path; |
| 246 } | 237 } |
| 247 | 238 |
| 248 void WebPluginDelegateImpl::InstallMissingPlugin() { | 239 void WebPluginDelegateImpl::InstallMissingPlugin() { |
| 249 NPEvent evt; | 240 NPEvent evt; |
| 250 instance()->NPP_HandleEvent(&evt); | 241 instance()->NPP_HandleEvent(&evt); |
| 251 } | 242 } |
| 252 | 243 |
| 253 void WebPluginDelegateImpl::WindowedUpdateGeometry( | |
| 254 const gfx::Rect& window_rect, | |
| 255 const gfx::Rect& clip_rect) { | |
| 256 if (WindowedReposition(window_rect, clip_rect) || | |
| 257 !windowed_did_set_window_) { | |
| 258 // Let the plugin know that it has been moved | |
| 259 WindowedSetWindow(); | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 bool WebPluginDelegateImpl::WindowedCreatePlugin() { | |
| 264 DCHECK(!windowed_handle_); | |
| 265 | |
| 266 // create window | |
| 267 if (windowed_handle_ == 0) | |
| 268 return false; | |
| 269 | |
| 270 return true; | |
| 271 } | |
| 272 | |
| 273 void WebPluginDelegateImpl::WindowedDestroyWindow() { | |
| 274 if (windowed_handle_ != NULL) { | |
| 275 // destroy the window | |
| 276 windowed_handle_ = 0; | |
| 277 } | |
| 278 } | |
| 279 | |
| 280 bool WebPluginDelegateImpl::WindowedReposition( | |
| 281 const gfx::Rect& window_rect, | |
| 282 const gfx::Rect& clip_rect) { | |
| 283 if (!windowed_handle_) { | |
| 284 NOTREACHED(); | |
| 285 return false; | |
| 286 } | |
| 287 | |
| 288 if (window_rect_ == window_rect && clip_rect_ == clip_rect) | |
| 289 return false; | |
| 290 | |
| 291 // Clipping is handled by WebPlugin. | |
| 292 if (window_rect.size() != window_rect_.size()) { | |
| 293 // resize window | |
| 294 } | |
| 295 | |
| 296 window_rect_ = window_rect; | |
| 297 clip_rect_ = clip_rect; | |
| 298 | |
| 299 // Ensure that the entire window gets repainted. | |
| 300 // invalidate entire window | |
| 301 | |
| 302 return true; | |
| 303 } | |
| 304 | |
| 305 void WebPluginDelegateImpl::WindowedSetWindow() { | |
| 306 if (!instance_) | |
| 307 return; | |
| 308 | |
| 309 if (!windowed_handle_) { | |
| 310 NOTREACHED(); | |
| 311 return; | |
| 312 } | |
| 313 | |
| 314 // instance()->set_window_handle(windowed_handle_); | |
| 315 | |
| 316 DCHECK(!instance()->windowless()); | |
| 317 | |
| 318 window_.clipRect.top = clip_rect_.y(); | |
| 319 window_.clipRect.left = clip_rect_.x(); | |
| 320 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); | |
| 321 window_.clipRect.right = clip_rect_.x() + clip_rect_.width(); | |
| 322 window_.height = window_rect_.height(); | |
| 323 window_.width = window_rect_.width(); | |
| 324 window_.x = window_rect_.x(); | |
| 325 window_.y = window_rect_.y(); | |
| 326 | |
| 327 cg_context_.context = NULL; | |
| 328 cg_context_.window = NULL; | |
| 329 window_.window = &cg_context_; | |
| 330 window_.type = NPWindowTypeDrawable; // NPWindowTypeWindow; | |
| 331 | |
| 332 // Reset this flag before entering the instance in case of side-effects. | |
| 333 windowed_did_set_window_ = true; | |
| 334 | |
| 335 NPError err = instance()->NPP_SetWindow(&window_); | |
| 336 } | |
| 337 | |
| 338 void WebPluginDelegateImpl::WindowlessUpdateGeometry( | 244 void WebPluginDelegateImpl::WindowlessUpdateGeometry( |
| 339 const gfx::Rect& window_rect, | 245 const gfx::Rect& window_rect, |
| 340 const gfx::Rect& clip_rect) { | 246 const gfx::Rect& clip_rect) { |
| 341 // Only resend to the instance if the geometry has changed. | 247 // Only resend to the instance if the geometry has changed. |
| 342 if (window_rect == window_rect_ && clip_rect == clip_rect_) | 248 if (window_rect == window_rect_ && clip_rect == clip_rect_) |
| 343 return; | 249 return; |
| 344 | 250 |
| 345 // We will inform the instance of this change when we call NPP_SetWindow. | 251 // We will inform the instance of this change when we call NPP_SetWindow. |
| 346 clip_rect_ = clip_rect; | 252 clip_rect_ = clip_rect; |
| 347 cutout_rects_.clear(); | 253 cutout_rects_.clear(); |
| 348 | 254 |
| 349 if (window_rect_ != window_rect) { | 255 if (window_rect_ != window_rect) { |
| 350 window_rect_ = window_rect; | 256 window_rect_ = window_rect; |
| 351 | 257 |
| 352 WindowlessSetWindow(true); | 258 window_.clipRect.top = clip_rect_.y(); |
| 353 | 259 window_.clipRect.left = clip_rect_.x(); |
| 354 NPEvent pos_changed_event; | 260 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); |
| 355 | 261 window_.clipRect.right = clip_rect_.x() + clip_rect_.width(); |
| 356 instance()->NPP_HandleEvent(&pos_changed_event); | 262 window_.height = window_rect_.height(); |
| 263 window_.width = window_rect_.width(); |
| 264 window_.x = window_rect_.x(); |
| 265 window_.y = window_rect_.y(); |
| 266 window_.type = NPWindowTypeDrawable; |
| 267 windowless_needs_set_window_ = true; |
| 357 } | 268 } |
| 358 } | 269 } |
| 359 | 270 |
| 360 void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext hdc, | 271 void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context, |
| 361 const gfx::Rect& damage_rect) { | 272 const gfx::Rect& damage_rect) { |
| 362 static StatsRate plugin_paint("Plugin.Paint"); | 273 static StatsRate plugin_paint("Plugin.Paint"); |
| 363 StatsScope<StatsRate> scope(plugin_paint); | 274 StatsScope<StatsRate> scope(plugin_paint); |
| 275 |
| 276 // We save and restore the NSGraphicsContext state in case the plugin uses |
| 277 // Cocoa drawing. |
| 278 [NSGraphicsContext saveGraphicsState]; |
| 279 [NSGraphicsContext setCurrentContext:[NSGraphicsContext |
| 280 graphicsContextWithGraphicsPort:context |
| 281 flipped:NO]]; |
| 282 |
| 283 CGContextSaveGState(context); |
| 284 cg_context_.context = context; |
| 285 window_.window = &cg_context_; |
| 286 window_.type = NPWindowTypeDrawable; |
| 287 if (windowless_needs_set_window_) { |
| 288 Rect window_bounds; |
| 289 window_bounds.top = window_rect_.y(); |
| 290 window_bounds.left = window_rect_.x(); |
| 291 window_bounds.bottom = window_rect_.y() + window_rect_.height(); |
| 292 window_bounds.right = window_rect_.x() + window_rect_.width(); |
| 293 if (!cg_context_.window) { |
| 294 // For all plugins we create a placeholder offscreen window for the use |
| 295 // of NPWindow. NPAPI on the Mac requires a Carbon WindowRef for the |
| 296 // "browser window", even if we're not using the Quickdraw drawing model. |
| 297 // Not having a valid window reference causes subtle bugs with plugins |
| 298 // which retreive the NPWindow and validate the same. The NPWindow |
| 299 // can be retreived via NPN_GetValue of NPNVnetscapeWindow. |
| 300 |
| 301 WindowRef window_ref; |
| 302 if (CreateNewWindow(kDocumentWindowClass, |
| 303 kWindowStandardDocumentAttributes, |
| 304 &window_bounds, |
| 305 &window_ref) == noErr) { |
| 306 cg_context_.window = window_ref; |
| 307 } |
| 308 } else { |
| 309 SetWindowBounds(cg_context_.window, kWindowContentRgn, &window_bounds); |
| 310 } |
| 311 instance()->NPP_SetWindow(&window_); |
| 312 windowless_needs_set_window_ = false; |
| 313 } |
| 364 NPEvent paint_event; | 314 NPEvent paint_event; |
| 315 paint_event.what = updateEvt; |
| 316 paint_event.message = reinterpret_cast<uint32>(cg_context_.window); |
| 317 paint_event.when = TickCount(); |
| 318 paint_event.where.h = 0; |
| 319 paint_event.where.v = 0; |
| 320 paint_event.modifiers = 0; |
| 365 instance()->NPP_HandleEvent(&paint_event); | 321 instance()->NPP_HandleEvent(&paint_event); |
| 322 CGContextRestoreGState(context); |
| 323 [NSGraphicsContext restoreGraphicsState]; |
| 366 } | 324 } |
| 367 | 325 |
| 368 void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) { | 326 void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) { |
| 369 if (!instance()) | 327 if (!instance()) |
| 370 return; | 328 return; |
| 371 | 329 |
| 372 if (window_rect_.IsEmpty()) // wait for geometry to be set. | 330 if (window_rect_.IsEmpty()) // wait for geometry to be set. |
| 373 return; | 331 return; |
| 374 | 332 |
| 375 DCHECK(instance()->windowless()); | |
| 376 | |
| 377 window_.clipRect.top = clip_rect_.y(); | 333 window_.clipRect.top = clip_rect_.y(); |
| 378 window_.clipRect.left = clip_rect_.x(); | 334 window_.clipRect.left = clip_rect_.x(); |
| 379 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); | 335 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); |
| 380 window_.clipRect.right = clip_rect_.x() + clip_rect_.width(); | 336 window_.clipRect.right = clip_rect_.x() + clip_rect_.width(); |
| 381 window_.height = window_rect_.height(); | 337 window_.height = window_rect_.height(); |
| 382 window_.width = window_rect_.width(); | 338 window_.width = window_rect_.width(); |
| 383 window_.x = window_rect_.x(); | 339 window_.x = window_rect_.x(); |
| 384 window_.y = window_rect_.y(); | 340 window_.y = window_rect_.y(); |
| 385 window_.type = NPWindowTypeDrawable; | 341 window_.type = NPWindowTypeDrawable; |
| 386 | 342 |
| 387 if (!force_set_window) | 343 if (!force_set_window) |
| 388 // Reset this flag before entering the instance in case of side-effects. | 344 // Reset this flag before entering the instance in case of side-effects. |
| 389 windowless_needs_set_window_ = false; | 345 windowless_needs_set_window_ = false; |
| 390 | 346 |
| 347 Rect window_bounds; |
| 348 window_bounds.top = window_rect_.y(); |
| 349 window_bounds.left = window_rect_.x(); |
| 350 window_bounds.bottom = window_rect_.y() + window_rect_.height(); |
| 351 window_bounds.right = window_rect_.x() + window_rect_.width(); |
| 352 if (!cg_context_.window) { |
| 353 // For all plugins we create a placeholder offscreen window for the use |
| 354 // of NPWindow. NPAPI on the Mac requires a Carbon WindowRef for the |
| 355 // "browser window", even if we're not using the Quickdraw drawing model. |
| 356 // Not having a valid window reference causes subtle bugs with plugins |
| 357 // which retreive the NPWindow and validate the same. The NPWindow |
| 358 // can be retreived via NPN_GetValue of NPNVnetscapeWindow. |
| 359 |
| 360 WindowRef window_ref; |
| 361 if (CreateNewWindow(kDocumentWindowClass, |
| 362 kWindowStandardDocumentAttributes, |
| 363 &window_bounds, |
| 364 &window_ref) == noErr) { |
| 365 cg_context_.window = window_ref; |
| 366 } |
| 367 } else { |
| 368 SetWindowBounds(cg_context_.window, kWindowContentRgn, &window_bounds); |
| 369 } |
| 370 |
| 391 NPError err = instance()->NPP_SetWindow(&window_); | 371 NPError err = instance()->NPP_SetWindow(&window_); |
| 392 DCHECK(err == NPERR_NO_ERROR); | 372 DCHECK(err == NPERR_NO_ERROR); |
| 393 } | 373 } |
| 394 | 374 |
| 395 void WebPluginDelegateImpl::SetFocus() { | 375 void WebPluginDelegateImpl::SetFocus() { |
| 396 DCHECK(instance()->windowless()); | 376 NPEvent focus_event = { 0 }; |
| 377 focus_event.what = NPEventType_GetFocusEvent; |
| 378 focus_event.when = TickCount(); |
| 379 instance()->NPP_HandleEvent(&focus_event); |
| 380 } |
| 397 | 381 |
| 398 NPEvent focus_event; | 382 static bool NPEventFromWebMouseEvent(const WebMouseEvent& event, |
| 383 NPEvent *np_event) { |
| 384 np_event->where.h = event.windowX; |
| 385 np_event->where.v = event.windowY; |
| 399 | 386 |
| 400 instance()->NPP_HandleEvent(&focus_event); | 387 if (event.modifiers & WebInputEvent::ControlKey) |
| 388 np_event->modifiers |= controlKey; |
| 389 if (event.modifiers & WebInputEvent::ShiftKey) |
| 390 np_event->modifiers |= shiftKey; |
| 391 |
| 392 switch (event.type) { |
| 393 case WebInputEvent::MouseMove: |
| 394 case WebInputEvent::MouseLeave: |
| 395 case WebInputEvent::MouseEnter: |
| 396 np_event->what = NPEventType_AdjustCursorEvent; |
| 397 return true; |
| 398 case WebInputEvent::MouseDown: |
| 399 switch (event.button) { |
| 400 case WebMouseEvent::ButtonLeft: |
| 401 case WebMouseEvent::ButtonMiddle: |
| 402 case WebMouseEvent::ButtonRight: |
| 403 np_event->what = mouseDown; |
| 404 break; |
| 405 } |
| 406 return true; |
| 407 case WebInputEvent::MouseUp: |
| 408 switch (event.button) { |
| 409 case WebMouseEvent::ButtonLeft: |
| 410 case WebMouseEvent::ButtonMiddle: |
| 411 case WebMouseEvent::ButtonRight: |
| 412 np_event->what = mouseUp; |
| 413 break; |
| 414 } |
| 415 return true; |
| 416 default: |
| 417 NOTREACHED(); |
| 418 return false; |
| 419 } |
| 420 } |
| 421 |
| 422 static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent& event, |
| 423 NPEvent *np_event) { |
| 424 np_event->message = event.nativeKeyCode; |
| 425 |
| 426 switch (event.type) { |
| 427 case WebInputEvent::KeyDown: |
| 428 np_event->what = keyDown; |
| 429 return true; |
| 430 case WebInputEvent::KeyUp: |
| 431 np_event->what = keyUp; |
| 432 return true; |
| 433 default: |
| 434 NOTREACHED(); |
| 435 return false; |
| 436 } |
| 437 } |
| 438 |
| 439 static bool NPEventFromWebInputEvent(const WebInputEvent& event, |
| 440 NPEvent* np_event) { |
| 441 switch (event.type) { |
| 442 case WebInputEvent::MouseMove: |
| 443 case WebInputEvent::MouseLeave: |
| 444 case WebInputEvent::MouseEnter: |
| 445 case WebInputEvent::MouseDown: |
| 446 case WebInputEvent::MouseUp: |
| 447 if (event.size < sizeof(WebMouseEvent)) { |
| 448 NOTREACHED(); |
| 449 return false; |
| 450 } |
| 451 return NPEventFromWebMouseEvent(*static_cast<const WebMouseEvent*>(&event)
, np_event); |
| 452 case WebInputEvent::KeyDown: |
| 453 case WebInputEvent::KeyUp: |
| 454 if (event.size < sizeof(WebKeyboardEvent)) { |
| 455 NOTREACHED(); |
| 456 return false; |
| 457 } |
| 458 return NPEventFromWebKeyboardEvent(*static_cast<const WebKeyboardEvent*>(&
event), np_event); |
| 459 default: |
| 460 DLOG(WARNING) << "unknown event type" << event.type; |
| 461 return false; |
| 462 } |
| 401 } | 463 } |
| 402 | 464 |
| 403 bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, | 465 bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, |
| 404 WebCursorInfo* cursor) { | 466 WebCursorInfo* cursor) { |
| 405 DCHECK(windowless_) << "events should only be received in windowless mode"; | 467 DCHECK(windowless_) << "events should only be received in windowless mode"; |
| 406 DCHECK(cursor != NULL); | 468 DCHECK(cursor != NULL); |
| 407 // TODO: convert event into a NPEvent, and call NPP_HandleEvent(np_event). | |
| 408 | 469 |
| 409 return true; | 470 NPEvent np_event = {0}; |
| 471 if (!NPEventFromWebInputEvent(event, &np_event)) { |
| 472 return false; |
| 473 } |
| 474 np_event.when = TickCount(); |
| 475 bool ret = instance()->NPP_HandleEvent(&np_event) != 0; |
| 476 return ret; |
| 410 } | 477 } |
| 411 | 478 |
| 412 WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( | 479 WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( |
| 413 int resource_id, const std::string &url, bool notify_needed, | 480 int resource_id, const std::string &url, bool notify_needed, |
| 414 intptr_t notify_data, intptr_t existing_stream) { | 481 intptr_t notify_data, intptr_t existing_stream) { |
| 415 // Stream already exists. This typically happens for range requests | 482 // Stream already exists. This typically happens for range requests |
| 416 // initiated via NPN_RequestRead. | 483 // initiated via NPN_RequestRead. |
| 417 if (existing_stream) { | 484 if (existing_stream) { |
| 418 NPAPI::PluginStream* plugin_stream = | 485 NPAPI::PluginStream* plugin_stream = |
| 419 reinterpret_cast<NPAPI::PluginStream*>(existing_stream); | 486 reinterpret_cast<NPAPI::PluginStream*>(existing_stream); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 433 return stream; | 500 return stream; |
| 434 } | 501 } |
| 435 | 502 |
| 436 void WebPluginDelegateImpl::URLRequestRouted(const std::string&url, | 503 void WebPluginDelegateImpl::URLRequestRouted(const std::string&url, |
| 437 bool notify_needed, | 504 bool notify_needed, |
| 438 intptr_t notify_data) { | 505 intptr_t notify_data) { |
| 439 if (notify_needed) { | 506 if (notify_needed) { |
| 440 instance()->SetURLLoadData(GURL(url.c_str()), notify_data); | 507 instance()->SetURLLoadData(GURL(url.c_str()), notify_data); |
| 441 } | 508 } |
| 442 } | 509 } |
| OLD | NEW |