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" |
11 #include "base/iat_patch.h" | 11 #include "base/iat_patch.h" |
12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
13 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
14 #include "base/stats_counters.h" | 14 #include "base/stats_counters.h" |
15 #include "base/string_util.h" | 15 #include "base/string_util.h" |
| 16 #include "webkit/api/public/WebInputEvent.h" |
16 #include "webkit/default_plugin/plugin_impl.h" | 17 #include "webkit/default_plugin/plugin_impl.h" |
17 #include "webkit/glue/glue_util.h" | 18 #include "webkit/glue/glue_util.h" |
18 #include "webkit/glue/webplugin.h" | 19 #include "webkit/glue/webplugin.h" |
19 #include "webkit/glue/plugins/plugin_constants_win.h" | 20 #include "webkit/glue/plugins/plugin_constants_win.h" |
20 #include "webkit/glue/plugins/plugin_instance.h" | 21 #include "webkit/glue/plugins/plugin_instance.h" |
21 #include "webkit/glue/plugins/plugin_lib.h" | 22 #include "webkit/glue/plugins/plugin_lib.h" |
22 #include "webkit/glue/plugins/plugin_list.h" | 23 #include "webkit/glue/plugins/plugin_list.h" |
23 #include "webkit/glue/plugins/plugin_stream_url.h" | 24 #include "webkit/glue/plugins/plugin_stream_url.h" |
24 #include "webkit/glue/webkit_glue.h" | 25 #include "webkit/glue/webkit_glue.h" |
25 | 26 |
| 27 using WebKit::WebKeyboardEvent; |
| 28 using WebKit::WebInputEvent; |
| 29 using WebKit::WebMouseEvent; |
| 30 |
26 namespace { | 31 namespace { |
27 | 32 |
28 const wchar_t kWebPluginDelegateProperty[] = L"WebPluginDelegateProperty"; | 33 const wchar_t kWebPluginDelegateProperty[] = L"WebPluginDelegateProperty"; |
29 const wchar_t kPluginNameAtomProperty[] = L"PluginNameAtom"; | 34 const wchar_t kPluginNameAtomProperty[] = L"PluginNameAtom"; |
30 const wchar_t kDummyActivationWindowName[] = L"DummyWindowForActivation"; | 35 const wchar_t kDummyActivationWindowName[] = L"DummyWindowForActivation"; |
31 const wchar_t kPluginOrigProc[] = L"OriginalPtr"; | 36 const wchar_t kPluginOrigProc[] = L"OriginalPtr"; |
32 const wchar_t kPluginFlashThrottle[] = L"FlashThrottle"; | 37 const wchar_t kPluginFlashThrottle[] = L"FlashThrottle"; |
33 | 38 |
34 // The fastest we are willing to process WM_USER+1 events for Flash. | 39 // The fastest we are willing to process WM_USER+1 events for Flash. |
35 // Flash can easily exceed the limits of our CPU if we don't throttle it. | 40 // Flash can easily exceed the limits of our CPU if we don't throttle it. |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 if (!start_result) | 258 if (!start_result) |
254 return false; | 259 return false; |
255 | 260 |
256 windowless_ = instance_->windowless(); | 261 windowless_ = instance_->windowless(); |
257 if (!windowless_) { | 262 if (!windowless_) { |
258 if (!WindowedCreatePlugin()) | 263 if (!WindowedCreatePlugin()) |
259 return false; | 264 return false; |
260 } | 265 } |
261 | 266 |
262 plugin->SetWindow(windowed_handle_); | 267 plugin->SetWindow(windowed_handle_); |
263 #if defined(OS_WIN) | |
264 if (windowless_) { | 268 if (windowless_) { |
265 // For windowless plugins we should set the containing window handle | 269 // For windowless plugins we should set the containing window handle |
266 // as the instance window handle. This is what Safari does. Not having | 270 // as the instance window handle. This is what Safari does. Not having |
267 // a valid window handle causes subtle bugs with plugins which retreive | 271 // a valid window handle causes subtle bugs with plugins which retreive |
268 // the window handle and validate the same. The window handle can be | 272 // the window handle and validate the same. The window handle can be |
269 // retreived via NPN_GetValue of NPNVnetscapeWindow. | 273 // retreived via NPN_GetValue of NPNVnetscapeWindow. |
270 instance_->set_window_handle(parent_); | 274 instance_->set_window_handle(parent_); |
| 275 #if defined(OS_WIN) |
271 CreateDummyWindowForActivation(); | 276 CreateDummyWindowForActivation(); |
272 handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); | 277 handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); |
273 plugin->SetWindowlessPumpEvent(handle_event_pump_messages_event_); | 278 plugin->SetWindowlessPumpEvent(handle_event_pump_messages_event_); |
| 279 #endif |
274 } | 280 } |
275 #endif | |
276 plugin_url_ = url.spec(); | 281 plugin_url_ = url.spec(); |
277 | 282 |
278 // The windowless version of the Silverlight plugin calls the | 283 // The windowless version of the Silverlight plugin calls the |
279 // WindowFromPoint API and passes the result of that to the | 284 // WindowFromPoint API and passes the result of that to the |
280 // TrackPopupMenu API call as the owner window. This causes the API | 285 // TrackPopupMenu API call as the owner window. This causes the API |
281 // to fail as the API expects the window handle to live on the same | 286 // to fail as the API expects the window handle to live on the same |
282 // thread as the caller. It works in the other browsers as the plugin | 287 // thread as the caller. It works in the other browsers as the plugin |
283 // lives on the browser thread. Our workaround is to intercept the | 288 // lives on the browser thread. Our workaround is to intercept the |
284 // TrackPopupMenu API for Silverlight and replace the window handle | 289 // TrackPopupMenu API for Silverlight and replace the window handle |
285 // with the dummy activation window. | 290 // with the dummy activation window. |
(...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
992 DCHECK(instance()->windowless()); | 997 DCHECK(instance()->windowless()); |
993 | 998 |
994 NPEvent focus_event; | 999 NPEvent focus_event; |
995 focus_event.event = WM_SETFOCUS; | 1000 focus_event.event = WM_SETFOCUS; |
996 focus_event.wParam = 0; | 1001 focus_event.wParam = 0; |
997 focus_event.lParam = 0; | 1002 focus_event.lParam = 0; |
998 | 1003 |
999 instance()->NPP_HandleEvent(&focus_event); | 1004 instance()->NPP_HandleEvent(&focus_event); |
1000 } | 1005 } |
1001 | 1006 |
1002 bool WebPluginDelegateImpl::HandleEvent(NPEvent* event, | 1007 static bool NPEventFromWebMouseEvent(const WebMouseEvent& event, |
1003 WebCursor* cursor) { | 1008 NPEvent *np_event) { |
| 1009 np_event->lParam = static_cast<uint32>(MAKELPARAM(event.windowX, |
| 1010 event.windowY)); |
| 1011 np_event->wParam = 0; |
| 1012 |
| 1013 if (event.modifiers & WebInputEvent::ControlKey) |
| 1014 np_event->wParam |= MK_CONTROL; |
| 1015 if (event.modifiers & WebInputEvent::ShiftKey) |
| 1016 np_event->wParam |= MK_SHIFT; |
| 1017 if (event.modifiers & WebInputEvent::LeftButtonDown) |
| 1018 np_event->wParam |= MK_LBUTTON; |
| 1019 if (event.modifiers & WebInputEvent::MiddleButtonDown) |
| 1020 np_event->wParam |= MK_MBUTTON; |
| 1021 if (event.modifiers & WebInputEvent::RightButtonDown) |
| 1022 np_event->wParam |= MK_RBUTTON; |
| 1023 |
| 1024 switch (event.type) { |
| 1025 case WebInputEvent::MouseMove: |
| 1026 case WebInputEvent::MouseLeave: |
| 1027 case WebInputEvent::MouseEnter: |
| 1028 np_event->event = WM_MOUSEMOVE; |
| 1029 return true; |
| 1030 case WebInputEvent::MouseDown: |
| 1031 switch (event.button) { |
| 1032 case WebMouseEvent::ButtonLeft: |
| 1033 np_event->event = WM_LBUTTONDOWN; |
| 1034 break; |
| 1035 case WebMouseEvent::ButtonMiddle: |
| 1036 np_event->event = WM_MBUTTONDOWN; |
| 1037 break; |
| 1038 case WebMouseEvent::ButtonRight: |
| 1039 np_event->event = WM_RBUTTONDOWN; |
| 1040 break; |
| 1041 } |
| 1042 return true; |
| 1043 case WebInputEvent::MouseUp: |
| 1044 switch (event.button) { |
| 1045 case WebMouseEvent::ButtonLeft: |
| 1046 np_event->event = WM_LBUTTONUP; |
| 1047 break; |
| 1048 case WebMouseEvent::ButtonMiddle: |
| 1049 np_event->event = WM_MBUTTONUP; |
| 1050 break; |
| 1051 case WebMouseEvent::ButtonRight: |
| 1052 np_event->event = WM_RBUTTONUP; |
| 1053 break; |
| 1054 } |
| 1055 return true; |
| 1056 default: |
| 1057 NOTREACHED(); |
| 1058 return false; |
| 1059 } |
| 1060 } |
| 1061 |
| 1062 static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent& event, |
| 1063 NPEvent *np_event) { |
| 1064 np_event->wParam = event.windowsKeyCode; |
| 1065 |
| 1066 switch (event.type) { |
| 1067 case WebInputEvent::KeyDown: |
| 1068 np_event->event = WM_KEYDOWN; |
| 1069 np_event->lParam = 0; |
| 1070 return true; |
| 1071 case WebInputEvent::KeyUp: |
| 1072 np_event->event = WM_KEYUP; |
| 1073 np_event->lParam = 0x8000; |
| 1074 return true; |
| 1075 default: |
| 1076 NOTREACHED(); |
| 1077 return false; |
| 1078 } |
| 1079 } |
| 1080 |
| 1081 static bool NPEventFromWebInputEvent(const WebInputEvent& event, |
| 1082 NPEvent* np_event) { |
| 1083 switch (event.type) { |
| 1084 case WebInputEvent::MouseMove: |
| 1085 case WebInputEvent::MouseLeave: |
| 1086 case WebInputEvent::MouseEnter: |
| 1087 case WebInputEvent::MouseDown: |
| 1088 case WebInputEvent::MouseUp: |
| 1089 if (event.size < sizeof(WebMouseEvent)) { |
| 1090 NOTREACHED(); |
| 1091 return false; |
| 1092 } |
| 1093 return NPEventFromWebMouseEvent( |
| 1094 *static_cast<const WebMouseEvent*>(&event), np_event); |
| 1095 case WebInputEvent::KeyDown: |
| 1096 case WebInputEvent::KeyUp: |
| 1097 if (event.size < sizeof(WebKeyboardEvent)) { |
| 1098 NOTREACHED(); |
| 1099 return false; |
| 1100 } |
| 1101 return NPEventFromWebKeyboardEvent( |
| 1102 *static_cast<const WebKeyboardEvent*>(&event), np_event); |
| 1103 default: |
| 1104 return false; |
| 1105 } |
| 1106 } |
| 1107 |
| 1108 bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, |
| 1109 WebCursor* cursor) { |
1004 DCHECK(windowless_) << "events should only be received in windowless mode"; | 1110 DCHECK(windowless_) << "events should only be received in windowless mode"; |
1005 DCHECK(cursor != NULL); | 1111 DCHECK(cursor != NULL); |
1006 | 1112 |
| 1113 NPEvent np_event; |
| 1114 if (!NPEventFromWebInputEvent(event, &np_event)) { |
| 1115 return false; |
| 1116 } |
| 1117 |
1007 // To ensure that the plugin receives keyboard events we set focus to the | 1118 // To ensure that the plugin receives keyboard events we set focus to the |
1008 // dummy window. | 1119 // dummy window. |
1009 // TODO(iyengar) We need a framework in the renderer to identify which | 1120 // TODO(iyengar) We need a framework in the renderer to identify which |
1010 // windowless plugin is under the mouse and to handle this. This would | 1121 // windowless plugin is under the mouse and to handle this. This would |
1011 // also require some changes in RenderWidgetHost to detect this in the | 1122 // also require some changes in RenderWidgetHost to detect this in the |
1012 // WM_MOUSEACTIVATE handler and inform the renderer accordingly. | 1123 // WM_MOUSEACTIVATE handler and inform the renderer accordingly. |
1013 HWND prev_focus_window = NULL; | 1124 HWND prev_focus_window = NULL; |
1014 if (event->event == WM_RBUTTONDOWN) { | 1125 if (np_event.event == WM_RBUTTONDOWN) { |
1015 prev_focus_window = ::SetFocus(dummy_window_for_activation_); | 1126 prev_focus_window = ::SetFocus(dummy_window_for_activation_); |
1016 } | 1127 } |
1017 | 1128 |
1018 if (ShouldTrackEventForModalLoops(event)) { | 1129 if (ShouldTrackEventForModalLoops(&np_event)) { |
1019 // A windowless plugin can enter a modal loop in a NPP_HandleEvent call. | 1130 // A windowless plugin can enter a modal loop in a NPP_HandleEvent call. |
1020 // For e.g. Flash puts up a context menu when we right click on the | 1131 // For e.g. Flash puts up a context menu when we right click on the |
1021 // windowless plugin area. We detect this by setting up a message filter | 1132 // windowless plugin area. We detect this by setting up a message filter |
1022 // hook pror to calling NPP_HandleEvent on the plugin and unhook on | 1133 // hook pror to calling NPP_HandleEvent on the plugin and unhook on |
1023 // return from NPP_HandleEvent. If the plugin does enter a modal loop | 1134 // return from NPP_HandleEvent. If the plugin does enter a modal loop |
1024 // in that context we unhook on receiving the first notification in | 1135 // in that context we unhook on receiving the first notification in |
1025 // the message filter hook. | 1136 // the message filter hook. |
1026 handle_event_message_filter_hook_ = | 1137 handle_event_message_filter_hook_ = |
1027 SetWindowsHookEx(WH_MSGFILTER, HandleEventMessageFilterHook, NULL, | 1138 SetWindowsHookEx(WH_MSGFILTER, HandleEventMessageFilterHook, NULL, |
1028 GetCurrentThreadId()); | 1139 GetCurrentThreadId()); |
1029 } | 1140 } |
1030 | 1141 |
1031 bool old_task_reentrancy_state = | 1142 bool old_task_reentrancy_state = |
1032 MessageLoop::current()->NestableTasksAllowed(); | 1143 MessageLoop::current()->NestableTasksAllowed(); |
1033 | 1144 |
1034 | 1145 |
1035 // Maintain a local/global stack for the g_current_plugin_instance variable | 1146 // Maintain a local/global stack for the g_current_plugin_instance variable |
1036 // as this may be a nested invocation. | 1147 // as this may be a nested invocation. |
1037 WebPluginDelegateImpl* last_plugin_instance = g_current_plugin_instance; | 1148 WebPluginDelegateImpl* last_plugin_instance = g_current_plugin_instance; |
1038 | 1149 |
1039 g_current_plugin_instance = this; | 1150 g_current_plugin_instance = this; |
1040 | 1151 |
1041 handle_event_depth_++; | 1152 handle_event_depth_++; |
1042 | 1153 |
1043 bool pop_user_gesture = false; | 1154 bool pop_user_gesture = false; |
1044 | 1155 |
1045 if (IsUserGestureMessage(event->event)) { | 1156 if (IsUserGestureMessage(np_event.event)) { |
1046 pop_user_gesture = true; | 1157 pop_user_gesture = true; |
1047 instance()->PushPopupsEnabledState(true); | 1158 instance()->PushPopupsEnabledState(true); |
1048 } | 1159 } |
1049 | 1160 |
1050 bool ret = instance()->NPP_HandleEvent(event) != 0; | 1161 bool ret = instance()->NPP_HandleEvent(&np_event) != 0; |
1051 | 1162 |
1052 if (event->event == WM_MOUSEMOVE) { | 1163 if (np_event.event == WM_MOUSEMOVE) { |
1053 // Snag a reference to the current cursor ASAP in case the plugin modified | 1164 // Snag a reference to the current cursor ASAP in case the plugin modified |
1054 // it. There is a nasty race condition here with the multiprocess browser | 1165 // it. There is a nasty race condition here with the multiprocess browser |
1055 // as someone might be setting the cursor in the main process as well. | 1166 // as someone might be setting the cursor in the main process as well. |
1056 *cursor = current_windowless_cursor_; | 1167 *cursor = current_windowless_cursor_; |
1057 } | 1168 } |
1058 | 1169 |
1059 if (pop_user_gesture) { | 1170 if (pop_user_gesture) { |
1060 instance()->PopPopupsEnabledState(); | 1171 instance()->PopPopupsEnabledState(); |
1061 } | 1172 } |
1062 | 1173 |
1063 handle_event_depth_--; | 1174 handle_event_depth_--; |
1064 | 1175 |
1065 g_current_plugin_instance = last_plugin_instance; | 1176 g_current_plugin_instance = last_plugin_instance; |
1066 | 1177 |
1067 MessageLoop::current()->SetNestableTasksAllowed(old_task_reentrancy_state); | 1178 MessageLoop::current()->SetNestableTasksAllowed(old_task_reentrancy_state); |
1068 | 1179 |
1069 if (handle_event_message_filter_hook_) { | 1180 if (handle_event_message_filter_hook_) { |
1070 UnhookWindowsHookEx(handle_event_message_filter_hook_); | 1181 UnhookWindowsHookEx(handle_event_message_filter_hook_); |
1071 handle_event_message_filter_hook_ = NULL; | 1182 handle_event_message_filter_hook_ = NULL; |
1072 } | 1183 } |
1073 | 1184 |
1074 // We could have multiple NPP_HandleEvent calls nested together in case | 1185 // We could have multiple NPP_HandleEvent calls nested together in case |
1075 // the plugin enters a modal loop. Reset the pump messages event when | 1186 // the plugin enters a modal loop. Reset the pump messages event when |
1076 // the outermost NPP_HandleEvent call unwinds. | 1187 // the outermost NPP_HandleEvent call unwinds. |
1077 if (handle_event_depth_ == 0) { | 1188 if (handle_event_depth_ == 0) { |
1078 ResetEvent(handle_event_pump_messages_event_); | 1189 ResetEvent(handle_event_pump_messages_event_); |
1079 } | 1190 } |
1080 | 1191 |
1081 if (event->event == WM_RBUTTONUP && ::IsWindow(prev_focus_window)) { | 1192 if (np_event.event == WM_RBUTTONUP && ::IsWindow(prev_focus_window)) { |
1082 ::SetFocus(prev_focus_window); | 1193 ::SetFocus(prev_focus_window); |
1083 } | 1194 } |
1084 | 1195 |
1085 return ret; | 1196 return ret; |
1086 } | 1197 } |
1087 | 1198 |
1088 WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( | 1199 WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( |
1089 int resource_id, const std::string &url, bool notify_needed, | 1200 int resource_id, const std::string &url, bool notify_needed, |
1090 intptr_t notify_data, intptr_t existing_stream) { | 1201 intptr_t notify_data, intptr_t existing_stream) { |
1091 // Stream already exists. This typically happens for range requests | 1202 // Stream already exists. This typically happens for range requests |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1183 | 1294 |
1184 // It is ok to pass NULL here to GetCursor as we are not looking for cursor | 1295 // It is ok to pass NULL here to GetCursor as we are not looking for cursor |
1185 // types defined by Webkit. | 1296 // types defined by Webkit. |
1186 HCURSOR previous_cursor = | 1297 HCURSOR previous_cursor = |
1187 g_current_plugin_instance->current_windowless_cursor_.GetCursor(NULL); | 1298 g_current_plugin_instance->current_windowless_cursor_.GetCursor(NULL); |
1188 | 1299 |
1189 g_current_plugin_instance->current_windowless_cursor_.InitFromExternalCursor( | 1300 g_current_plugin_instance->current_windowless_cursor_.InitFromExternalCursor( |
1190 cursor); | 1301 cursor); |
1191 return previous_cursor; | 1302 return previous_cursor; |
1192 } | 1303 } |
OLD | NEW |