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