OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 #ifndef WEBKIT_PLUGINS_NPAPI_WEBPLUGIN_DELEGATE_IMPL_H_ | |
6 #define WEBKIT_PLUGINS_NPAPI_WEBPLUGIN_DELEGATE_IMPL_H_ | |
7 | |
8 #include <string> | |
9 #include <vector> | |
10 | |
11 #include "base/memory/ref_counted.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/memory/weak_ptr.h" | |
14 #include "base/sequenced_task_runner_helpers.h" | |
15 #include "base/timer/timer.h" | |
16 #include "build/build_config.h" | |
17 #include "third_party/npapi/bindings/npapi.h" | |
18 #include "ui/gfx/native_widget_types.h" | |
19 #include "ui/gfx/rect.h" | |
20 #include "webkit/common/cursors/webcursor.h" | |
21 #include "webkit/plugins/npapi/webplugin_delegate.h" | |
22 #include "webkit/plugins/webkit_plugins_export.h" | |
23 | |
24 #if defined(USE_X11) | |
25 #include "ui/base/x/x11_util.h" | |
26 | |
27 typedef struct _GdkDrawable GdkPixmap; | |
28 #endif | |
29 | |
30 namespace base { | |
31 class FilePath; | |
32 } | |
33 | |
34 #if defined(OS_MACOSX) | |
35 #ifdef __OBJC__ | |
36 @class CALayer; | |
37 @class CARenderer; | |
38 #else | |
39 class CALayer; | |
40 class CARenderer; | |
41 #endif | |
42 #endif | |
43 | |
44 namespace webkit { | |
45 namespace npapi { | |
46 | |
47 class PluginInstance; | |
48 | |
49 #if defined(OS_MACOSX) | |
50 class WebPluginAcceleratedSurface; | |
51 class ExternalDragTracker; | |
52 #endif // OS_MACOSX | |
53 | |
54 #if defined(OS_WIN) | |
55 class WebPluginIMEWin; | |
56 #endif // OS_WIN | |
57 | |
58 // An implementation of WebPluginDelegate that runs in the plugin process, | |
59 // proxied from the renderer by WebPluginDelegateProxy. | |
60 class WEBKIT_PLUGINS_EXPORT WebPluginDelegateImpl : public WebPluginDelegate { | |
61 public: | |
62 enum PluginQuirks { | |
63 PLUGIN_QUIRK_SETWINDOW_TWICE = 1, // Win32 | |
64 PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE = 2, // Win32 | |
65 PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY = 4, // Win32 | |
66 PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY = 8, // Win32 | |
67 PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES = 16, // Win32 | |
68 PLUGIN_QUIRK_DIE_AFTER_UNLOAD = 32, // Win32 | |
69 PLUGIN_QUIRK_PATCH_SETCURSOR = 64, // Win32 | |
70 PLUGIN_QUIRK_BLOCK_NONSTANDARD_GETURL_REQUESTS = 128, // Win32 | |
71 PLUGIN_QUIRK_WINDOWLESS_OFFSET_WINDOW_TO_DRAW = 256, // Linux | |
72 PLUGIN_QUIRK_WINDOWLESS_INVALIDATE_AFTER_SET_WINDOW = 512, // Linux | |
73 PLUGIN_QUIRK_NO_WINDOWLESS = 1024, // Windows | |
74 PLUGIN_QUIRK_PATCH_REGENUMKEYEXW = 2048, // Windows | |
75 PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS = 4096, // Windows | |
76 PLUGIN_QUIRK_HANDLE_MOUSE_CAPTURE = 16384, // Windows | |
77 PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK = 32768, // Linux | |
78 PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL = 65536, // Windows. | |
79 PLUGIN_QUIRK_EMULATE_IME = 131072, // Windows. | |
80 }; | |
81 | |
82 static WebPluginDelegateImpl* Create(const base::FilePath& filename, | |
83 const std::string& mime_type); | |
84 | |
85 #if defined(OS_WIN) | |
86 static bool IsPluginDelegateWindow(HWND window); | |
87 static bool GetPluginNameFromWindow(HWND window, | |
88 base::string16* plugin_name); | |
89 static bool GetPluginVersionFromWindow(HWND window, | |
90 base::string16* plugin_version); | |
91 | |
92 // Returns true if the window handle passed in is that of the dummy | |
93 // activation window for windowless plugins. | |
94 static bool IsDummyActivationWindow(HWND window); | |
95 | |
96 // Returns the default HWND to parent the windowed plugins and dummy windows | |
97 // for activation to when none isavailable. | |
98 static HWND GetDefaultWindowParent(); | |
99 #endif | |
100 | |
101 // WebPluginDelegate implementation | |
102 virtual bool Initialize(const GURL& url, | |
103 const std::vector<std::string>& arg_names, | |
104 const std::vector<std::string>& arg_values, | |
105 WebPlugin* plugin, | |
106 bool load_manually) OVERRIDE; | |
107 virtual void PluginDestroyed() OVERRIDE; | |
108 virtual void UpdateGeometry(const gfx::Rect& window_rect, | |
109 const gfx::Rect& clip_rect) OVERRIDE; | |
110 virtual void Paint(WebKit::WebCanvas* canvas, const gfx::Rect& rect) OVERRIDE; | |
111 virtual void SetFocus(bool focused) OVERRIDE; | |
112 virtual bool HandleInputEvent(const WebKit::WebInputEvent& event, | |
113 WebCursor::CursorInfo* cursor_info) OVERRIDE; | |
114 virtual NPObject* GetPluginScriptableObject() OVERRIDE; | |
115 virtual NPP GetPluginNPP() OVERRIDE; | |
116 virtual bool GetFormValue(base::string16* value) OVERRIDE; | |
117 virtual void DidFinishLoadWithReason(const GURL& url, | |
118 NPReason reason, | |
119 int notify_id) OVERRIDE; | |
120 virtual int GetProcessId() OVERRIDE; | |
121 virtual void SendJavaScriptStream(const GURL& url, | |
122 const std::string& result, | |
123 bool success, | |
124 int notify_id) OVERRIDE; | |
125 virtual void DidReceiveManualResponse(const GURL& url, | |
126 const std::string& mime_type, | |
127 const std::string& headers, | |
128 uint32 expected_length, | |
129 uint32 last_modified) OVERRIDE; | |
130 virtual void DidReceiveManualData(const char* buffer, int length) OVERRIDE; | |
131 virtual void DidFinishManualLoading() OVERRIDE; | |
132 virtual void DidManualLoadFail() OVERRIDE; | |
133 virtual WebPluginResourceClient* CreateResourceClient( | |
134 unsigned long resource_id, const GURL& url, int notify_id) OVERRIDE; | |
135 virtual WebPluginResourceClient* CreateSeekableResourceClient( | |
136 unsigned long resource_id, int range_request_id) OVERRIDE; | |
137 // End of WebPluginDelegate implementation. | |
138 | |
139 gfx::PluginWindowHandle windowed_handle() const { return windowed_handle_; } | |
140 bool IsWindowless() const { return windowless_; } | |
141 PluginInstance* instance() { return instance_.get(); } | |
142 gfx::Rect GetRect() const { return window_rect_; } | |
143 gfx::Rect GetClipRect() const { return clip_rect_; } | |
144 | |
145 // Returns the path for the library implementing this plugin. | |
146 base::FilePath GetPluginPath(); | |
147 | |
148 // Returns a combination of PluginQuirks. | |
149 int GetQuirks() const { return quirks_; } | |
150 | |
151 // Informs the plugin that the view it is in has gained or lost focus. | |
152 void SetContentAreaHasFocus(bool has_focus); | |
153 | |
154 #if defined(OS_WIN) | |
155 // Informs the plug-in that an IME has changed its status. | |
156 void ImeCompositionUpdated(const base::string16& text, | |
157 const std::vector<int>& clauses, | |
158 const std::vector<int>& target, | |
159 int cursor_position); | |
160 | |
161 // Informs the plugin that IME composition has completed./ If |text| is empty, | |
162 // IME was cancelled. | |
163 void ImeCompositionCompleted(const base::string16& text); | |
164 | |
165 // Returns the IME status retrieved from a plug-in. | |
166 bool GetIMEStatus(int* input_type, gfx::Rect* caret_rect); | |
167 #endif | |
168 | |
169 #if defined(OS_MACOSX) && !defined(USE_AURA) | |
170 // Informs the plugin that the geometry has changed, as with UpdateGeometry, | |
171 // but also includes the new buffer context for that new geometry. | |
172 void UpdateGeometryAndContext(const gfx::Rect& window_rect, | |
173 const gfx::Rect& clip_rect, | |
174 gfx::NativeDrawingContext context); | |
175 // Informs the delegate that the plugin called NPN_Invalidate*. Used as a | |
176 // trigger for Core Animation drawing. | |
177 void PluginDidInvalidate(); | |
178 // Returns the delegate currently processing events. | |
179 static WebPluginDelegateImpl* GetActiveDelegate(); | |
180 // Informs the plugin that the window it is in has gained or lost focus. | |
181 void SetWindowHasFocus(bool has_focus); | |
182 // Informs the plugin that its tab or window has been hidden or shown. | |
183 void SetContainerVisibility(bool is_visible); | |
184 // Informs the plugin that its containing window's frame has changed. | |
185 // Frames are in screen coordinates. | |
186 void WindowFrameChanged(const gfx::Rect& window_frame, | |
187 const gfx::Rect& view_frame); | |
188 // Informs the plugin that IME composition has completed. | |
189 // If |text| is empty, IME was cancelled. | |
190 void ImeCompositionCompleted(const base::string16& text); | |
191 // Informs the delegate that the plugin set a Cocoa NSCursor. | |
192 void SetNSCursor(NSCursor* cursor); | |
193 | |
194 // Indicates that the windowless plugins will draw directly to the window | |
195 // context instead of a buffer context. | |
196 void SetNoBufferContext(); | |
197 | |
198 // TODO(caryclark): This is a temporary workaround to allow the Darwin / Skia | |
199 // port to share code with the Darwin / CG port. Later, this will be removed | |
200 // and all callers will use the Paint defined above. | |
201 void CGPaint(CGContextRef context, const gfx::Rect& rect); | |
202 #endif // OS_MACOSX && !USE_AURA | |
203 | |
204 #if defined(USE_X11) | |
205 void SetWindowlessShmPixmap(XID shm_pixmap) { | |
206 windowless_shm_pixmap_ = shm_pixmap; | |
207 } | |
208 #endif | |
209 | |
210 private: | |
211 friend class base::DeleteHelper<WebPluginDelegateImpl>; | |
212 friend class WebPluginDelegate; | |
213 | |
214 explicit WebPluginDelegateImpl(PluginInstance* instance); | |
215 virtual ~WebPluginDelegateImpl(); | |
216 | |
217 // Called by Initialize() for platform-specific initialization. | |
218 // If this returns false, the plugin shouldn't be started--see Initialize(). | |
219 bool PlatformInitialize(); | |
220 | |
221 // Called by DestroyInstance(), used for platform-specific destruction. | |
222 void PlatformDestroyInstance(); | |
223 | |
224 //-------------------------- | |
225 // used for windowed plugins | |
226 void WindowedUpdateGeometry(const gfx::Rect& window_rect, | |
227 const gfx::Rect& clip_rect); | |
228 // Create the native window. | |
229 // Returns true if the window is created (or already exists). | |
230 // Returns false if unable to create the window. | |
231 bool WindowedCreatePlugin(); | |
232 | |
233 // Destroy the native window. | |
234 void WindowedDestroyWindow(); | |
235 | |
236 // Reposition the native window to be in sync with the given geometry. | |
237 // Returns true if the native window has moved or been clipped differently. | |
238 bool WindowedReposition(const gfx::Rect& window_rect, | |
239 const gfx::Rect& clip_rect); | |
240 | |
241 // Tells the plugin about the current state of the window. | |
242 // See NPAPI NPP_SetWindow for more information. | |
243 void WindowedSetWindow(); | |
244 | |
245 #if defined(OS_WIN) | |
246 // Registers the window class for our window | |
247 ATOM RegisterNativeWindowClass(); | |
248 | |
249 // Our WndProc functions. | |
250 static LRESULT CALLBACK WrapperWindowProc( | |
251 HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); | |
252 static LRESULT CALLBACK NativeWndProc( | |
253 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); | |
254 static LRESULT CALLBACK FlashWindowlessWndProc( | |
255 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); | |
256 static LRESULT CALLBACK DummyWindowProc( | |
257 HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); | |
258 | |
259 // Used for throttling Flash messages. | |
260 static void ClearThrottleQueueForWindow(HWND window); | |
261 static void OnThrottleMessage(); | |
262 static void ThrottleMessage(WNDPROC proc, HWND hwnd, UINT message, | |
263 WPARAM wParam, LPARAM lParam); | |
264 #endif | |
265 | |
266 //---------------------------- | |
267 // used for windowless plugins | |
268 void WindowlessUpdateGeometry(const gfx::Rect& window_rect, | |
269 const gfx::Rect& clip_rect); | |
270 void WindowlessPaint(gfx::NativeDrawingContext hdc, const gfx::Rect& rect); | |
271 | |
272 // Tells the plugin about the current state of the window. | |
273 // See NPAPI NPP_SetWindow for more information. | |
274 void WindowlessSetWindow(); | |
275 | |
276 // Informs the plugin that it has gained or lost keyboard focus (on the Mac, | |
277 // this just means window first responder status). | |
278 void SetPluginHasFocus(bool focused); | |
279 | |
280 // Handles the platform specific details of setting plugin focus. Returns | |
281 // false if the platform cancelled the focus tranfer. | |
282 bool PlatformSetPluginHasFocus(bool focused); | |
283 | |
284 //----------------------------------------- | |
285 // used for windowed and windowless plugins | |
286 | |
287 // Does platform-specific event handling. Arguments and return are identical | |
288 // to HandleInputEvent. | |
289 bool PlatformHandleInputEvent(const WebKit::WebInputEvent& event, | |
290 WebCursor::CursorInfo* cursor_info); | |
291 | |
292 // Closes down and destroys our plugin instance. | |
293 void DestroyInstance(); | |
294 | |
295 | |
296 // used for windowed plugins | |
297 // Note: on Mac OS X, the only time the windowed handle is non-zero | |
298 // is the case of accelerated rendering, which uses a fake window handle to | |
299 // identify itself back to the browser. It still performs all of its | |
300 // work offscreen. | |
301 gfx::PluginWindowHandle windowed_handle_; | |
302 gfx::Rect windowed_last_pos_; | |
303 | |
304 bool windowed_did_set_window_; | |
305 | |
306 // used by windowed and windowless plugins | |
307 bool windowless_; | |
308 | |
309 WebPlugin* plugin_; | |
310 scoped_refptr<PluginInstance> instance_; | |
311 | |
312 #if defined(OS_WIN) | |
313 // Original wndproc before we subclassed. | |
314 WNDPROC plugin_wnd_proc_; | |
315 | |
316 // Used to throttle WM_USER+1 messages in Flash. | |
317 uint32 last_message_; | |
318 bool is_calling_wndproc; | |
319 | |
320 // An IME emulator used by a windowless plug-in to retrieve IME data through | |
321 // IMM32 functions. | |
322 scoped_ptr<WebPluginIMEWin> plugin_ime_; | |
323 #endif // defined(OS_WIN) | |
324 | |
325 #if defined(USE_X11) | |
326 // The SHM pixmap for a windowless plugin. | |
327 XID windowless_shm_pixmap_; | |
328 #endif | |
329 | |
330 #if defined(TOOLKIT_GTK) | |
331 // The pixmap we're drawing into, for a windowless plugin. | |
332 GdkPixmap* pixmap_; | |
333 double first_event_time_; | |
334 | |
335 // On Linux some plugins assume that the GtkSocket container is in the same | |
336 // process. So we create a GtkPlug to plug into the browser's container, and | |
337 // a GtkSocket to hold the plugin. We then send the GtkPlug to the browser | |
338 // process. | |
339 GtkWidget* plug_; | |
340 GtkWidget* socket_; | |
341 | |
342 // Ensure pixmap_ exists and is at least width by height pixels. | |
343 void EnsurePixmapAtLeastSize(int width, int height); | |
344 #endif | |
345 | |
346 NPWindow window_; | |
347 gfx::Rect window_rect_; | |
348 gfx::Rect clip_rect_; | |
349 int quirks_; | |
350 | |
351 #if defined(OS_WIN) | |
352 // Windowless plugins don't have keyboard focus causing issues with the | |
353 // plugin not receiving keyboard events if the plugin enters a modal | |
354 // loop like TrackPopupMenuEx or MessageBox, etc. | |
355 // This is a basic issue with windows activation and focus arising due to | |
356 // the fact that these windows are created by different threads. Activation | |
357 // and focus are thread specific states, and if the browser has focus, | |
358 // the plugin may not have focus. | |
359 // To fix a majority of these activation issues we create a dummy visible | |
360 // child window to which we set focus whenever the windowless plugin | |
361 // receives a WM_LBUTTONDOWN/WM_RBUTTONDOWN message via NPP_HandleEvent. | |
362 | |
363 HWND dummy_window_for_activation_; | |
364 HWND dummy_window_parent_; | |
365 WNDPROC old_dummy_window_proc_; | |
366 bool CreateDummyWindowForActivation(); | |
367 | |
368 // Returns true if the event passed in needs to be tracked for a potential | |
369 // modal loop. | |
370 static bool ShouldTrackEventForModalLoops(NPEvent* event); | |
371 | |
372 // The message filter hook procedure, which tracks modal loops entered by | |
373 // a plugin in the course of a NPP_HandleEvent call. | |
374 static LRESULT CALLBACK HandleEventMessageFilterHook(int code, WPARAM wParam, | |
375 LPARAM lParam); | |
376 | |
377 // TrackPopupMenu interceptor. Parameters are the same as the Win32 function | |
378 // TrackPopupMenu. | |
379 static BOOL WINAPI TrackPopupMenuPatch(HMENU menu, unsigned int flags, int x, | |
380 int y, int reserved, HWND window, | |
381 const RECT* rect); | |
382 | |
383 // SetCursor interceptor for windowless plugins. | |
384 static HCURSOR WINAPI SetCursorPatch(HCURSOR cursor); | |
385 | |
386 // RegEnumKeyExW interceptor. | |
387 static LONG WINAPI RegEnumKeyExWPatch( | |
388 HKEY key, DWORD index, LPWSTR name, LPDWORD name_size, LPDWORD reserved, | |
389 LPWSTR class_name, LPDWORD class_size, PFILETIME last_write_time); | |
390 | |
391 // GetProcAddress intercepter for windowless plugins. | |
392 static FARPROC WINAPI GetProcAddressPatch(HMODULE module, LPCSTR name); | |
393 | |
394 // The mouse hook proc which handles mouse capture in windowed plugins. | |
395 static LRESULT CALLBACK MouseHookProc(int code, WPARAM wParam, | |
396 LPARAM lParam); | |
397 | |
398 // Calls SetCapture/ReleaseCapture based on the message type. | |
399 static void HandleCaptureForMessage(HWND window, UINT message); | |
400 | |
401 #elif defined(OS_MACOSX) && !defined(USE_AURA) | |
402 // Sets window_rect_ to |rect| | |
403 void SetPluginRect(const gfx::Rect& rect); | |
404 // Sets content_area_origin to |origin| | |
405 void SetContentAreaOrigin(const gfx::Point& origin); | |
406 // Updates everything that depends on the plugin's absolute screen location. | |
407 void PluginScreenLocationChanged(); | |
408 // Updates anything that depends on plugin visibility. | |
409 void PluginVisibilityChanged(); | |
410 | |
411 // Starts an IME session. | |
412 void StartIme(); | |
413 | |
414 // Informs the browser about the updated accelerated drawing surface. | |
415 void UpdateAcceleratedSurface(); | |
416 | |
417 // Uses a CARenderer to draw the plug-in's layer in our OpenGL surface. | |
418 void DrawLayerInSurface(); | |
419 | |
420 bool use_buffer_context_; | |
421 CGContextRef buffer_context_; // Weak ref. | |
422 | |
423 CALayer* layer_; // Used for CA drawing mode. Weak, retained by plug-in. | |
424 WebPluginAcceleratedSurface* surface_; // Weak ref. | |
425 CARenderer* renderer_; // Renders layer_ to surface_. | |
426 scoped_ptr<base::RepeatingTimer<WebPluginDelegateImpl> > redraw_timer_; | |
427 | |
428 // The upper-left corner of the web content area in screen coordinates, | |
429 // relative to an upper-left (0,0). | |
430 gfx::Point content_area_origin_; | |
431 | |
432 bool containing_window_has_focus_; | |
433 bool initial_window_focus_; | |
434 bool container_is_visible_; | |
435 bool have_called_set_window_; | |
436 | |
437 gfx::Rect cached_clip_rect_; | |
438 | |
439 bool ime_enabled_; | |
440 int keyup_ignore_count_; | |
441 | |
442 scoped_ptr<ExternalDragTracker> external_drag_tracker_; | |
443 #endif // OS_MACOSX && !USE_AURA | |
444 | |
445 // Called by the message filter hook when the plugin enters a modal loop. | |
446 void OnModalLoopEntered(); | |
447 | |
448 // Returns true if the message passed in corresponds to a user gesture. | |
449 static bool IsUserGesture(const WebKit::WebInputEvent& event); | |
450 | |
451 // The url with which the plugin was instantiated. | |
452 std::string plugin_url_; | |
453 | |
454 #if defined(OS_WIN) | |
455 // Indicates the end of a user gesture period. | |
456 void OnUserGestureEnd(); | |
457 | |
458 // Handle to the message filter hook | |
459 HHOOK handle_event_message_filter_hook_; | |
460 | |
461 // Event which is set when the plugin enters a modal loop in the course | |
462 // of a NPP_HandleEvent call. | |
463 HANDLE handle_event_pump_messages_event_; | |
464 | |
465 // This flag indicates whether we started tracking a user gesture message. | |
466 bool user_gesture_message_posted_; | |
467 | |
468 // Runnable Method Factory used to invoke the OnUserGestureEnd method | |
469 // asynchronously. | |
470 base::WeakPtrFactory<WebPluginDelegateImpl> user_gesture_msg_factory_; | |
471 | |
472 // Handle to the mouse hook installed for certain windowed plugins like | |
473 // flash. | |
474 HHOOK mouse_hook_; | |
475 #endif | |
476 | |
477 // Holds the depth of the HandleEvent callstack. | |
478 int handle_event_depth_; | |
479 | |
480 // Holds the current cursor set by the windowless plugin. | |
481 WebCursor current_windowless_cursor_; | |
482 | |
483 // Set to true initially and indicates if this is the first npp_setwindow | |
484 // call received by the plugin. | |
485 bool first_set_window_call_; | |
486 | |
487 // True if the plugin thinks it has keyboard focus | |
488 bool plugin_has_focus_; | |
489 // True if the plugin element has focus within the web content, regardless of | |
490 // whether its containing view currently has focus. | |
491 bool has_webkit_focus_; | |
492 // True if the containing view currently has focus. | |
493 // Initially set to true so that plugin focus still works in environments | |
494 // where SetContentAreaHasFocus is never called. See | |
495 // https://bugs.webkit.org/show_bug.cgi?id=46013 for details. | |
496 bool containing_view_has_focus_; | |
497 | |
498 // True if NPP_New did not return an error. | |
499 bool creation_succeeded_; | |
500 | |
501 DISALLOW_COPY_AND_ASSIGN(WebPluginDelegateImpl); | |
502 }; | |
503 | |
504 } // namespace npapi | |
505 } // namespace webkit | |
506 | |
507 #endif // WEBKIT_PLUGINS_NPAPI_WEBPLUGIN_DELEGATE_IMPL_H_ | |
OLD | NEW |