1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: sw=4 ts=4 et :
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Plugin App.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Ben Turner <bent.mozilla@gmail.com>.
20 : * Portions created by the Initial Developer are Copyright (C) 2009
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Chris Jones <jones.chris.g@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef dom_plugins_PluginModuleChild_h
41 : #define dom_plugins_PluginModuleChild_h 1
42 :
43 : #include "mozilla/Attributes.h"
44 :
45 : #include <string>
46 : #include <vector>
47 :
48 : #include "base/basictypes.h"
49 :
50 : #include "prlink.h"
51 :
52 : #include "npapi.h"
53 : #include "npfunctions.h"
54 :
55 : #include "nsAutoPtr.h"
56 : #include "nsDataHashtable.h"
57 : #include "nsTHashtable.h"
58 : #include "nsHashKeys.h"
59 :
60 : #ifdef MOZ_WIDGET_COCOA
61 : #include "PluginInterposeOSX.h"
62 : #endif
63 :
64 : #include "mozilla/plugins/PPluginModuleChild.h"
65 : #include "mozilla/plugins/PluginInstanceChild.h"
66 : #include "mozilla/plugins/PluginIdentifierChild.h"
67 :
68 : // NOTE: stolen from nsNPAPIPlugin.h
69 :
70 : /*
71 : * Use this macro before each exported function
72 : * (between the return address and the function
73 : * itself), to ensure that the function has the
74 : * right calling conventions on OS/2.
75 : */
76 : #ifdef XP_OS2
77 : #define NP_CALLBACK _System
78 : #else
79 : #define NP_CALLBACK
80 : #endif
81 :
82 : #if defined(XP_WIN)
83 : #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (__stdcall * _name)
84 : #elif defined(XP_OS2)
85 : #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (_System * _name)
86 : #else
87 : #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (* _name)
88 : #endif
89 :
90 : typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_GETENTRYPOINTS) (NPPluginFuncs* pCallbacks);
91 : typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGININIT) (const NPNetscapeFuncs* pCallbacks);
92 : typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINUNIXINIT) (const NPNetscapeFuncs* pCallbacks, NPPluginFuncs* fCallbacks);
93 : typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) (void);
94 :
95 : namespace mozilla {
96 : namespace dom {
97 : class PCrashReporterChild;
98 : }
99 :
100 : namespace plugins {
101 :
102 : #ifdef MOZ_WIDGET_QT
103 : class NestedLoopTimer;
104 : static const int kNestedLoopDetectorIntervalMs = 90;
105 : #endif
106 :
107 : class PluginScriptableObjectChild;
108 : class PluginInstanceChild;
109 :
110 : class PluginModuleChild : public PPluginModuleChild
111 : {
112 : typedef mozilla::dom::PCrashReporterChild PCrashReporterChild;
113 : protected:
114 : NS_OVERRIDE
115 : virtual mozilla::ipc::RPCChannel::RacyRPCPolicy
116 0 : MediateRPCRace(const Message& parent, const Message& child)
117 : {
118 0 : return MediateRace(parent, child);
119 : }
120 :
121 : NS_OVERRIDE
122 : virtual bool ShouldContinueFromReplyTimeout();
123 :
124 : // Implement the PPluginModuleChild interface
125 : virtual bool AnswerNP_GetEntryPoints(NPError* rv);
126 : virtual bool AnswerNP_Initialize(const uint32_t& aFlags, NPError* rv);
127 :
128 : virtual PPluginIdentifierChild*
129 : AllocPPluginIdentifier(const nsCString& aString,
130 : const int32_t& aInt,
131 : const bool& aTemporary);
132 :
133 : virtual bool
134 : RecvPPluginIdentifierConstructor(PPluginIdentifierChild* actor,
135 : const nsCString& aString,
136 : const int32_t& aInt,
137 : const bool& aTemporary);
138 :
139 : virtual bool
140 : DeallocPPluginIdentifier(PPluginIdentifierChild* aActor);
141 :
142 : virtual PPluginInstanceChild*
143 : AllocPPluginInstance(const nsCString& aMimeType,
144 : const uint16_t& aMode,
145 : const InfallibleTArray<nsCString>& aNames,
146 : const InfallibleTArray<nsCString>& aValues,
147 : NPError* rv);
148 :
149 : virtual bool
150 : DeallocPPluginInstance(PPluginInstanceChild* aActor);
151 :
152 : virtual bool
153 : AnswerPPluginInstanceConstructor(PPluginInstanceChild* aActor,
154 : const nsCString& aMimeType,
155 : const uint16_t& aMode,
156 : const InfallibleTArray<nsCString>& aNames,
157 : const InfallibleTArray<nsCString>& aValues,
158 : NPError* rv);
159 : virtual bool
160 : AnswerNP_Shutdown(NPError *rv);
161 :
162 : virtual bool
163 : AnswerOptionalFunctionsSupported(bool *aURLRedirectNotify,
164 : bool *aClearSiteData,
165 : bool *aGetSitesWithData);
166 :
167 : virtual bool
168 : AnswerNPP_ClearSiteData(const nsCString& aSite,
169 : const uint64_t& aFlags,
170 : const uint64_t& aMaxAge,
171 : NPError* aResult);
172 :
173 : virtual bool
174 : AnswerNPP_GetSitesWithData(InfallibleTArray<nsCString>* aResult);
175 :
176 : virtual bool
177 : RecvSetAudioSessionData(const nsID& aId,
178 : const nsString& aDisplayName,
179 : const nsString& aIconPath);
180 :
181 : virtual bool
182 : RecvSetParentHangTimeout(const uint32_t& aSeconds);
183 :
184 : virtual PCrashReporterChild*
185 : AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
186 : PRUint32* processType);
187 : virtual bool
188 : DeallocPCrashReporter(PCrashReporterChild* actor);
189 : virtual bool
190 : AnswerPCrashReporterConstructor(PCrashReporterChild* actor,
191 : mozilla::dom::NativeThreadId* id,
192 : PRUint32* processType);
193 :
194 : virtual void
195 : ActorDestroy(ActorDestroyReason why);
196 :
197 : MOZ_NORETURN void QuickExit();
198 :
199 : NS_OVERRIDE virtual bool
200 : RecvProcessNativeEventsInRPCCall();
201 :
202 : public:
203 : PluginModuleChild();
204 : virtual ~PluginModuleChild();
205 :
206 : // aPluginFilename is UTF8, not native-charset!
207 : bool Init(const std::string& aPluginFilename,
208 : base::ProcessHandle aParentProcessHandle,
209 : MessageLoop* aIOLoop,
210 : IPC::Channel* aChannel);
211 :
212 : void CleanUp();
213 :
214 : const char* GetUserAgent();
215 :
216 : static const NPNetscapeFuncs sBrowserFuncs;
217 :
218 : static PluginModuleChild* current();
219 :
220 : bool RegisterActorForNPObject(NPObject* aObject,
221 : PluginScriptableObjectChild* aActor);
222 :
223 : void UnregisterActorForNPObject(NPObject* aObject);
224 :
225 : PluginScriptableObjectChild* GetActorForNPObject(NPObject* aObject);
226 :
227 : #ifdef DEBUG
228 : bool NPObjectIsRegistered(NPObject* aObject);
229 : #endif
230 :
231 : bool AsyncDrawingAllowed() { return mAsyncDrawingAllowed; }
232 :
233 : /**
234 : * The child implementation of NPN_CreateObject.
235 : */
236 : static NPObject* NP_CALLBACK NPN_CreateObject(NPP aNPP, NPClass* aClass);
237 : /**
238 : * The child implementation of NPN_RetainObject.
239 : */
240 : static NPObject* NP_CALLBACK NPN_RetainObject(NPObject* aNPObj);
241 : /**
242 : * The child implementation of NPN_ReleaseObject.
243 : */
244 : static void NP_CALLBACK NPN_ReleaseObject(NPObject* aNPObj);
245 :
246 : /**
247 : * The child implementations of NPIdentifier-related functions.
248 : */
249 : static NPIdentifier NP_CALLBACK NPN_GetStringIdentifier(const NPUTF8* aName);
250 : static void NP_CALLBACK NPN_GetStringIdentifiers(const NPUTF8** aNames,
251 : int32_t aNameCount,
252 : NPIdentifier* aIdentifiers);
253 : static NPIdentifier NP_CALLBACK NPN_GetIntIdentifier(int32_t aIntId);
254 : static bool NP_CALLBACK NPN_IdentifierIsString(NPIdentifier aIdentifier);
255 : static NPUTF8* NP_CALLBACK NPN_UTF8FromIdentifier(NPIdentifier aIdentifier);
256 : static int32_t NP_CALLBACK NPN_IntFromIdentifier(NPIdentifier aIdentifier);
257 :
258 : #ifdef MOZ_WIDGET_COCOA
259 : void ProcessNativeEvents();
260 :
261 : void PluginShowWindow(uint32_t window_id, bool modal, CGRect r) {
262 : SendPluginShowWindow(window_id, modal, r.origin.x, r.origin.y, r.size.width, r.size.height);
263 : }
264 :
265 : void PluginHideWindow(uint32_t window_id) {
266 : SendPluginHideWindow(window_id);
267 : }
268 :
269 : void SetCursor(NSCursorInfo& cursorInfo) {
270 : SendSetCursor(cursorInfo);
271 : }
272 :
273 : void ShowCursor(bool show) {
274 : SendShowCursor(show);
275 : }
276 :
277 : void PushCursor(NSCursorInfo& cursorInfo) {
278 : SendPushCursor(cursorInfo);
279 : }
280 :
281 : void PopCursor() {
282 : SendPopCursor();
283 : }
284 :
285 : bool GetNativeCursorsSupported() {
286 : bool supported = false;
287 : SendGetNativeCursorsSupported(&supported);
288 : return supported;
289 : }
290 : #endif
291 :
292 : // Quirks mode support for various plugin mime types
293 : enum PluginQuirks {
294 : QUIRKS_NOT_INITIALIZED = 0,
295 : // Silverlight assumes it is transparent in windowless mode. This quirk
296 : // matches the logic in nsNPAPIPluginInstance::SetWindowless.
297 : QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT = 1 << 0,
298 : // Win32: Hook TrackPopupMenu api so that we can swap out parent
299 : // hwnds. The api will fail with parents not associated with our
300 : // child ui thread. See WinlessHandleEvent for details.
301 : QUIRK_WINLESS_TRACKPOPUP_HOOK = 1 << 1,
302 : // Win32: Throttle flash WM_USER+1 heart beat messages to prevent
303 : // flooding chromium's dispatch loop, which can cause ipc traffic
304 : // processing lag.
305 : QUIRK_FLASH_THROTTLE_WMUSER_EVENTS = 1 << 2,
306 : // Win32: Catch resets on our subclass by hooking SetWindowLong.
307 : QUIRK_FLASH_HOOK_SETLONGPTR = 1 << 3,
308 : // X11: Work around a bug in Flash up to 10.1 d51 at least, where
309 : // expose event top left coordinates within the plugin-rect and
310 : // not at the drawable origin are misinterpreted.
311 : QUIRK_FLASH_EXPOSE_COORD_TRANSLATION = 1 << 4,
312 : // Win32: Catch get window info calls on the browser and tweak the
313 : // results so mouse input works when flash is displaying it's settings
314 : // window.
315 : QUIRK_FLASH_HOOK_GETWINDOWINFO = 1 << 5,
316 : // Win: Addresses a flash bug with mouse capture and full screen
317 : // windows.
318 : QUIRK_FLASH_FIXUP_MOUSE_CAPTURE = 1 << 6,
319 : // Win: QuickTime steals focus on SetWindow calls even if it's hidden.
320 : // Avoid calling SetWindow in that case.
321 : QUIRK_QUICKTIME_AVOID_SETWINDOW = 1 << 7,
322 : // Win: Check to make sure the parent window has focus before calling
323 : // set focus on the child. Addresses a full screen dialog prompt
324 : // problem in Silverlight.
325 : QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT = 1 << 8,
326 : // Mac: Allow the plugin to use offline renderer mode.
327 : // Use this only if the plugin is certified the support the offline renderer.
328 : QUIRK_ALLOW_OFFLINE_RENDERER = 1 << 9,
329 : };
330 :
331 : int GetQuirks() { return mQuirks; }
332 :
333 : private:
334 0 : void AddQuirk(PluginQuirks quirk) {
335 0 : if (mQuirks == QUIRKS_NOT_INITIALIZED)
336 0 : mQuirks = 0;
337 0 : mQuirks |= quirk;
338 0 : }
339 : void InitQuirksModes(const nsCString& aMimeType);
340 : bool InitGraphics();
341 : void DeinitGraphics();
342 : #if defined(MOZ_WIDGET_GTK2)
343 : static gboolean DetectNestedEventLoop(gpointer data);
344 : static gboolean ProcessBrowserEvents(gpointer data);
345 :
346 : NS_OVERRIDE
347 : virtual void EnteredCxxStack();
348 : NS_OVERRIDE
349 : virtual void ExitedCxxStack();
350 : #elif defined(MOZ_WIDGET_QT)
351 :
352 : NS_OVERRIDE
353 : virtual void EnteredCxxStack();
354 : NS_OVERRIDE
355 : virtual void ExitedCxxStack();
356 : #endif
357 :
358 : PRLibrary* mLibrary;
359 : nsCString mPluginFilename; // UTF8
360 : nsCString mUserAgent;
361 : int mQuirks;
362 : bool mAsyncDrawingAllowed;
363 :
364 : // we get this from the plugin
365 : NP_PLUGINSHUTDOWN mShutdownFunc;
366 : #ifdef OS_LINUX
367 : NP_PLUGINUNIXINIT mInitializeFunc;
368 : #elif defined(OS_WIN) || defined(OS_MACOSX)
369 : NP_PLUGININIT mInitializeFunc;
370 : NP_GETENTRYPOINTS mGetEntryPointsFunc;
371 : #endif
372 :
373 : NPPluginFuncs mFunctions;
374 : NPSavedData mSavedData;
375 :
376 : #if defined(MOZ_WIDGET_GTK2)
377 : // If a plugin spins a nested glib event loop in response to a
378 : // synchronous IPC message from the browser, the loop might break
379 : // only after the browser responds to a request sent by the
380 : // plugin. This can happen if a plugin uses gtk's synchronous
381 : // copy/paste, for example. But because the browser is blocked on
382 : // a condvar, it can't respond to the request. This situation
383 : // isn't technically a deadlock, but the symptoms are basically
384 : // the same from the user's perspective.
385 : //
386 : // We take two steps to prevent this
387 : //
388 : // (1) Detect nested event loops spun by the plugin. This is
389 : // done by scheduling a glib timer event in the plugin
390 : // process whenever the browser might block on the plugin.
391 : // If the plugin indeed spins a nested loop, this timer event
392 : // will fire "soon" thereafter.
393 : //
394 : // (2) When a nested loop is detected, deschedule the
395 : // nested-loop-detection timer and in its place, schedule
396 : // another timer that periodically calls back into the
397 : // browser and spins a mini event loop. This mini event loop
398 : // processes a handful of pending native events.
399 : //
400 : // Because only timer (1) or (2) (or neither) may be active at any
401 : // point in time, we use the same member variable
402 : // |mNestedLoopTimerId| to refer to both.
403 : //
404 : // When the browser no longer might be blocked on a plugin's IPC
405 : // response, we deschedule whichever of (1) or (2) is active.
406 : guint mNestedLoopTimerId;
407 : # ifdef DEBUG
408 : // Depth of the stack of calls to g_main_context_dispatch before any
409 : // nested loops are run. This is 1 when IPC calls are dispatched from
410 : // g_main_context_iteration, or 0 when dispatched directly from
411 : // MessagePumpForUI.
412 : int mTopLoopDepth;
413 : # endif
414 : #elif defined (MOZ_WIDGET_QT)
415 : NestedLoopTimer *mNestedLoopTimerObject;
416 : #endif
417 :
418 : struct NPObjectData : public nsPtrHashKey<NPObject>
419 0 : {
420 0 : NPObjectData(const NPObject* key)
421 : : nsPtrHashKey<NPObject>(key)
422 : , instance(NULL)
423 0 : , actor(NULL)
424 0 : { }
425 :
426 : // never NULL
427 : PluginInstanceChild* instance;
428 :
429 : // sometimes NULL (no actor associated with an NPObject)
430 : PluginScriptableObjectChild* actor;
431 : };
432 : /**
433 : * mObjectMap contains all the currently active NPObjects (from NPN_CreateObject until the
434 : * final release/dealloc, whether or not an actor is currently associated with the object.
435 : */
436 : nsTHashtable<NPObjectData> mObjectMap;
437 :
438 : friend class PluginIdentifierChild;
439 : friend class PluginIdentifierChildString;
440 : friend class PluginIdentifierChildInt;
441 : nsDataHashtable<nsCStringHashKey, PluginIdentifierChildString*> mStringIdentifiers;
442 : nsDataHashtable<nsUint32HashKey, PluginIdentifierChildInt*> mIntIdentifiers;
443 :
444 : public: // called by PluginInstanceChild
445 : /**
446 : * Dealloc an NPObject after last-release or when the associated instance
447 : * is destroyed. This function will remove the object from mObjectMap.
448 : */
449 : static void DeallocNPObject(NPObject* o);
450 :
451 : NPError NPP_Destroy(PluginInstanceChild* instance) {
452 : return mFunctions.destroy(instance->GetNPP(), 0);
453 : }
454 :
455 : /**
456 : * Fill PluginInstanceChild.mDeletingHash with all the remaining NPObjects
457 : * associated with that instance.
458 : */
459 : void FindNPObjectsForInstance(PluginInstanceChild* instance);
460 :
461 : private:
462 : static PLDHashOperator CollectForInstance(NPObjectData* d, void* userArg);
463 :
464 : #if defined(OS_WIN)
465 : NS_OVERRIDE
466 : virtual void EnteredCall();
467 : NS_OVERRIDE
468 : virtual void ExitedCall();
469 :
470 : // Entered/ExitedCall notifications keep track of whether the plugin has
471 : // entered a nested event loop within this RPC call.
472 : struct IncallFrame
473 : {
474 : IncallFrame()
475 : : _spinning(false)
476 : , _savedNestableTasksAllowed(false)
477 : { }
478 :
479 : bool _spinning;
480 : bool _savedNestableTasksAllowed;
481 : };
482 :
483 : nsAutoTArray<IncallFrame, 8> mIncallPumpingStack;
484 :
485 : static LRESULT CALLBACK NestedInputEventHook(int code,
486 : WPARAM wParam,
487 : LPARAM lParam);
488 : static LRESULT CALLBACK CallWindowProcHook(int code,
489 : WPARAM wParam,
490 : LPARAM lParam);
491 : void SetEventHooks();
492 : void ResetEventHooks();
493 : HHOOK mNestedEventHook;
494 : HHOOK mGlobalCallWndProcHook;
495 : #endif
496 : };
497 :
498 : } /* namespace plugins */
499 : } /* namespace mozilla */
500 :
501 : #endif // ifndef dom_plugins_PluginModuleChild_h
|