Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(642)

Side by Side Diff: webkit/glue/plugins/webplugin_delegate_impl.cc

Issue 115330: linux: Adding events to windowless plugins on Linux (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « webkit/glue/plugins/webplugin_delegate_impl.h ('k') | webkit/glue/plugins/webplugin_delegate_impl_gtk.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698