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 23 namespace base { 24 class FilePath; 25 } 26 27 #if defined(OS_MACOSX) 28 #ifdef __OBJC__ 29 @class CALayer; 30 @class CARenderer; 31 #else 32 class CALayer; 33 class CARenderer; 34 #endif 35 #endif 36 37 namespace content { 38 class PluginInstance; 39 class WebPlugin; 40 41 #if defined(OS_MACOSX) 42 class WebPluginAcceleratedSurface; 43 class ExternalDragTracker; 44 #endif // OS_MACOSX 45 46 #if defined(OS_WIN) 47 class WebPluginIMEWin; 48 #endif // OS_WIN 49 50 // An implementation of WebPluginDelegate that runs in the plugin process, 51 // proxied from the renderer by WebPluginDelegateProxy. 52 class 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