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 #include "webkit/glue/plugins/webplugin_delegate_impl.h" | 5 #include "webkit/glue/plugins/webplugin_delegate_impl.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
(...skipping 29 matching lines...) Expand all Loading... |
40 // I'd like to make the throttle delay variable, based on the amount of | 40 // I'd like to make the throttle delay variable, based on the amount of |
41 // time currently required to paint Flash plugins. There isn't a good | 41 // time currently required to paint Flash plugins. There isn't a good |
42 // way to count the time spent in aggregate plugin painting, however, so | 42 // way to count the time spent in aggregate plugin painting, however, so |
43 // this seems to work well enough. | 43 // this seems to work well enough. |
44 static const int kFlashWMUSERMessageThrottleDelayMs = 5; | 44 static const int kFlashWMUSERMessageThrottleDelayMs = 5; |
45 | 45 |
46 std::list<MSG> WebPluginDelegateImpl::throttle_queue_; | 46 std::list<MSG> WebPluginDelegateImpl::throttle_queue_; |
47 | 47 |
48 WebPluginDelegateImpl* WebPluginDelegateImpl::current_plugin_instance_ = NULL; | 48 WebPluginDelegateImpl* WebPluginDelegateImpl::current_plugin_instance_ = NULL; |
49 | 49 |
| 50 bool WebPluginDelegateImpl::track_popup_menu_patched_ = false; |
| 51 iat_patch::IATPatchFunction WebPluginDelegateImpl::iat_patch_helper_; |
| 52 |
50 WebPluginDelegateImpl* WebPluginDelegateImpl::Create( | 53 WebPluginDelegateImpl* WebPluginDelegateImpl::Create( |
51 const std::wstring& filename, | 54 const std::wstring& filename, |
52 const std::string& mime_type, | 55 const std::string& mime_type, |
53 HWND containing_window) { | 56 HWND containing_window) { |
54 scoped_refptr<NPAPI::PluginLib> plugin = | 57 scoped_refptr<NPAPI::PluginLib> plugin = |
55 NPAPI::PluginLib::CreatePluginLib(filename); | 58 NPAPI::PluginLib::CreatePluginLib(filename); |
56 if (plugin.get() == NULL) | 59 if (plugin.get() == NULL) |
57 return NULL; | 60 return NULL; |
58 | 61 |
59 NPError err = plugin->NP_Initialize(); | 62 NPError err = plugin->NP_Initialize(); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 plugin_wnd_proc_(NULL), | 133 plugin_wnd_proc_(NULL), |
131 last_message_(0), | 134 last_message_(0), |
132 is_calling_wndproc(false), | 135 is_calling_wndproc(false), |
133 initial_plugin_resize_done_(false), | 136 initial_plugin_resize_done_(false), |
134 dummy_window_for_activation_(NULL), | 137 dummy_window_for_activation_(NULL), |
135 handle_event_message_filter_hook_(NULL), | 138 handle_event_message_filter_hook_(NULL), |
136 handle_event_pump_messages_event_(NULL), | 139 handle_event_pump_messages_event_(NULL), |
137 handle_event_depth_(0), | 140 handle_event_depth_(0), |
138 user_gesture_message_posted_(false), | 141 user_gesture_message_posted_(false), |
139 #pragma warning(suppress: 4355) // can use this | 142 #pragma warning(suppress: 4355) // can use this |
140 user_gesture_msg_factory_(this) { | 143 user_gesture_msg_factory_(this), |
| 144 plugin_module_handle_(NULL) { |
141 memset(&window_, 0, sizeof(window_)); | 145 memset(&window_, 0, sizeof(window_)); |
142 | 146 |
143 const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info(); | 147 const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info(); |
144 std::wstring filename = file_util::GetFilenameFromPath(plugin_info.file); | 148 std::wstring filename = file_util::GetFilenameFromPath(plugin_info.file); |
145 | 149 |
146 if (instance_->mime_type() == "application/x-shockwave-flash" || | 150 if (instance_->mime_type() == "application/x-shockwave-flash" || |
147 filename == L"npswf32.dll") { | 151 filename == L"npswf32.dll") { |
148 // Flash only requests windowless plugins if we return a Mozilla user | 152 // Flash only requests windowless plugins if we return a Mozilla user |
149 // agent. | 153 // agent. |
150 instance_->set_use_mozilla_user_agent(); | 154 instance_->set_use_mozilla_user_agent(); |
(...skipping 15 matching lines...) Expand all Loading... |
166 } else if (instance_->mime_type() == "audio/x-pn-realaudio-plugin" || | 170 } else if (instance_->mime_type() == "audio/x-pn-realaudio-plugin" || |
167 filename == L"nppl3260.dll") { | 171 filename == L"nppl3260.dll") { |
168 quirks_ |= PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY; | 172 quirks_ |= PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY; |
169 } else if (plugin_info.name.find(L"VLC Multimedia Plugin") != | 173 } else if (plugin_info.name.find(L"VLC Multimedia Plugin") != |
170 std::wstring::npos) { | 174 std::wstring::npos) { |
171 // VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window | 175 // VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window |
172 // handle | 176 // handle |
173 quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY; | 177 quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY; |
174 // VLC 0.8.6d and 0.8.6e crash if multiple instances are created. | 178 // VLC 0.8.6d and 0.8.6e crash if multiple instances are created. |
175 quirks_ |= PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES; | 179 quirks_ |= PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES; |
| 180 } else if (filename == L"npctrl.dll") { |
| 181 // Explanation for this quirk can be found in |
| 182 // WebPluginDelegateImpl::Initialize. |
| 183 quirks_ |= PLUGIN_QUIRK_PATCH_TRACKPOPUP_MENU; |
176 } | 184 } |
| 185 |
| 186 plugin_module_handle_ = ::GetModuleHandle(filename.c_str()); |
177 } | 187 } |
178 | 188 |
179 WebPluginDelegateImpl::~WebPluginDelegateImpl() { | 189 WebPluginDelegateImpl::~WebPluginDelegateImpl() { |
180 if (::IsWindow(dummy_window_for_activation_)) { | 190 if (::IsWindow(dummy_window_for_activation_)) { |
181 ::DestroyWindow(dummy_window_for_activation_); | 191 ::DestroyWindow(dummy_window_for_activation_); |
182 } | 192 } |
183 | 193 |
184 DestroyInstance(); | 194 DestroyInstance(); |
185 | 195 |
186 if (!windowless_) | 196 if (!windowless_) |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 // retreived via NPN_GetValue of NPNVnetscapeWindow. | 243 // retreived via NPN_GetValue of NPNVnetscapeWindow. |
234 instance_->set_window_handle(parent_); | 244 instance_->set_window_handle(parent_); |
235 CreateDummyWindowForActivation(); | 245 CreateDummyWindowForActivation(); |
236 handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); | 246 handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); |
237 } else { | 247 } else { |
238 if (!WindowedCreatePlugin()) | 248 if (!WindowedCreatePlugin()) |
239 return false; | 249 return false; |
240 } | 250 } |
241 | 251 |
242 plugin->SetWindow(windowed_handle_, handle_event_pump_messages_event_); | 252 plugin->SetWindow(windowed_handle_, handle_event_pump_messages_event_); |
| 253 plugin_url_ = url.spec(); |
243 | 254 |
244 plugin_url_ = url.spec(); | 255 // The windowless version of the Silverlight plugin calls the |
| 256 // WindowFromPoint API and passes the result of that to the |
| 257 // TrackPopupMenu API call as the owner window. This causes the API |
| 258 // to fail as the API expects the window handle to live on the same |
| 259 // thread as the caller. It works in the other browsers as the plugin |
| 260 // lives on the browser thread. Our workaround is to intercept the |
| 261 // TrackPopupMenu API for Silverlight and replace the window handle |
| 262 // with the dummy activation window. |
| 263 if (windowless_ && !track_popup_menu_patched_ && |
| 264 (quirks_ & PLUGIN_QUIRK_PATCH_TRACKPOPUP_MENU)) { |
| 265 iat_patch_helper_.Patch(plugin_module_handle_, "user32.dll", |
| 266 "TrackPopupMenu", |
| 267 WebPluginDelegateImpl::TrackPopupMenuPatch); |
| 268 track_popup_menu_patched_ = true; |
| 269 } |
245 return true; | 270 return true; |
246 } | 271 } |
247 | 272 |
248 void WebPluginDelegateImpl::DestroyInstance() { | 273 void WebPluginDelegateImpl::DestroyInstance() { |
249 if (instance_ && (instance_->npp()->ndata != NULL)) { | 274 if (instance_ && (instance_->npp()->ndata != NULL)) { |
250 // Shutdown all streams before destroying so that | 275 // Shutdown all streams before destroying so that |
251 // no streams are left "in progress". Need to do | 276 // no streams are left "in progress". Need to do |
252 // this before calling set_web_plugin(NULL) because the | 277 // this before calling set_web_plugin(NULL) because the |
253 // instance uses the helper to do the download. | 278 // instance uses the helper to do the download. |
254 instance_->CloseStreams(); | 279 instance_->CloseStreams(); |
(...skipping 741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
996 handle_event_message_filter_hook_ = NULL; | 1021 handle_event_message_filter_hook_ = NULL; |
997 } | 1022 } |
998 | 1023 |
999 // We could have multiple NPP_HandleEvent calls nested together in case | 1024 // We could have multiple NPP_HandleEvent calls nested together in case |
1000 // the plugin enters a modal loop. Reset the pump messages event when | 1025 // the plugin enters a modal loop. Reset the pump messages event when |
1001 // the outermost NPP_HandleEvent call unwinds. | 1026 // the outermost NPP_HandleEvent call unwinds. |
1002 if (handle_event_depth_ == 0) { | 1027 if (handle_event_depth_ == 0) { |
1003 ResetEvent(handle_event_pump_messages_event_); | 1028 ResetEvent(handle_event_pump_messages_event_); |
1004 } | 1029 } |
1005 | 1030 |
1006 if (::IsWindow(prev_focus_window)) { | 1031 if (event->event == WM_RBUTTONUP && ::IsWindow(prev_focus_window)) { |
1007 ::SetFocus(prev_focus_window); | 1032 ::SetFocus(prev_focus_window); |
1008 } | 1033 } |
1009 | 1034 |
1010 if (WM_MOUSEMOVE == event->event) { | 1035 if (WM_MOUSEMOVE == event->event) { |
1011 cursor->InitFromCursor(last_cursor); | 1036 cursor->InitFromCursor(last_cursor); |
1012 } | 1037 } |
1013 | 1038 |
1014 return ret; | 1039 return ret; |
1015 } | 1040 } |
1016 | 1041 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1076 break; | 1101 break; |
1077 } | 1102 } |
1078 | 1103 |
1079 return false; | 1104 return false; |
1080 } | 1105 } |
1081 | 1106 |
1082 void WebPluginDelegateImpl::OnUserGestureEnd() { | 1107 void WebPluginDelegateImpl::OnUserGestureEnd() { |
1083 user_gesture_message_posted_ = false; | 1108 user_gesture_message_posted_ = false; |
1084 instance()->PopPopupsEnabledState(); | 1109 instance()->PopPopupsEnabledState(); |
1085 } | 1110 } |
| 1111 |
| 1112 BOOL WINAPI WebPluginDelegateImpl::TrackPopupMenuPatch( |
| 1113 HMENU menu, unsigned int flags, int x, int y, int reserved, |
| 1114 HWND window, const RECT* rect) { |
| 1115 if (current_plugin_instance_) { |
| 1116 unsigned long window_process_id = 0; |
| 1117 unsigned long window_thread_id = |
| 1118 GetWindowThreadProcessId(window, &window_process_id); |
| 1119 // TrackPopupMenu fails if the window passed in belongs to a different |
| 1120 // thread. |
| 1121 if (::GetCurrentThreadId() != window_thread_id) { |
| 1122 window = current_plugin_instance_->dummy_window_for_activation_; |
| 1123 } |
| 1124 } |
| 1125 return TrackPopupMenu(menu, flags, x, y, reserved, window, rect); |
| 1126 } |
OLD | NEW |