1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef nsNPAPIPluginInstance_h_
7 #define nsNPAPIPluginInstance_h_
8 
9 #include "nsSize.h"
10 #include "nsCOMPtr.h"
11 #include "nsTArray.h"
12 #include "nsPIDOMWindow.h"
13 #include "nsITimer.h"
14 #include "nsIPluginInstanceOwner.h"
15 #include "nsIURI.h"
16 #include "nsIChannel.h"
17 #include "nsHashKeys.h"
18 #include <prinrval.h>
19 #include "js/TypeDecls.h"
20 #include "nsIAudioChannelAgent.h"
21 #ifdef MOZ_WIDGET_ANDROID
22 #include "nsIRunnable.h"
23 #include "GLContextTypes.h"
24 #include "AndroidSurfaceTexture.h"
25 #include "AndroidBridge.h"
26 #include <map>
27 class PluginEventRunnable;
28 #endif
29 
30 #include "mozilla/EventForwards.h"
31 #include "mozilla/TimeStamp.h"
32 #include "mozilla/PluginLibrary.h"
33 #include "mozilla/RefPtr.h"
34 #include "mozilla/WeakPtr.h"
35 
36 class nsPluginStreamListenerPeer; // browser-initiated stream class
37 class nsNPAPIPluginStreamListener; // plugin-initiated stream class
38 class nsIPluginInstanceOwner;
39 class nsIOutputStream;
40 class nsPluginInstanceOwner;
41 
42 #if defined(OS_WIN)
43 const NPDrawingModel kDefaultDrawingModel = NPDrawingModelSyncWin;
44 #elif defined(MOZ_X11)
45 const NPDrawingModel kDefaultDrawingModel = NPDrawingModelSyncX;
46 #elif defined(XP_MACOSX)
47 #ifndef NP_NO_QUICKDRAW
48 const NPDrawingModel kDefaultDrawingModel = NPDrawingModelQuickDraw; // Not supported
49 #else
50 const NPDrawingModel kDefaultDrawingModel = NPDrawingModelCoreGraphics;
51 #endif
52 #else
53 const NPDrawingModel kDefaultDrawingModel = static_cast<NPDrawingModel>(0);
54 #endif
55 
56 /**
57  * Used to indicate whether it's OK to reenter Gecko and repaint, flush frames,
58  * run scripts, etc, during this plugin call.
59  * When NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO is set, we try to avoid dangerous
60  * Gecko activities when the plugin spins a nested event loop, on a best-effort
61  * basis.
62  */
63 enum NSPluginCallReentry {
64   NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO,
65   NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO
66 };
67 
68 class nsNPAPITimer
69 {
70 public:
71   NPP npp;
72   uint32_t id;
73   nsCOMPtr<nsITimer> timer;
74   void (*callback)(NPP npp, uint32_t timerID);
75   bool inCallback;
76   bool needUnschedule;
77 };
78 
79 class nsNPAPIPluginInstance final : public nsIAudioChannelAgentCallback
80                                   , public mozilla::SupportsWeakPtr<nsNPAPIPluginInstance>
81 {
82 private:
83   typedef mozilla::PluginLibrary PluginLibrary;
84 
85 public:
86   typedef mozilla::gfx::DrawTarget DrawTarget;
87 
88   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsNPAPIPluginInstance)
89   NS_DECL_THREADSAFE_ISUPPORTS
90   NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK
91 
92   nsresult Initialize(nsNPAPIPlugin *aPlugin, nsPluginInstanceOwner* aOwner, const nsACString& aMIMEType);
93   nsresult Start();
94   nsresult Stop();
95   nsresult SetWindow(NPWindow* window);
96   nsresult NewStreamFromPlugin(const char* type, const char* target, nsIOutputStream* *result);
97   nsresult Print(NPPrint* platformPrint);
98   nsresult HandleEvent(void* event, int16_t* result,
99                        NSPluginCallReentry aSafeToReenterGecko = NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
100   nsresult GetValueFromPlugin(NPPVariable variable, void* value);
101   nsresult GetDrawingModel(int32_t* aModel);
102   nsresult IsRemoteDrawingCoreAnimation(bool* aDrawing);
103   nsresult ContentsScaleFactorChanged(double aContentsScaleFactor);
104   nsresult CSSZoomFactorChanged(float aCSSZoomFactor);
105   nsresult GetJSObject(JSContext *cx, JSObject** outObject);
106   bool ShouldCache();
107   nsresult IsWindowless(bool* isWindowless);
108   nsresult AsyncSetWindow(NPWindow* window);
109   nsresult GetImageContainer(mozilla::layers::ImageContainer **aContainer);
110   nsresult GetImageSize(nsIntSize* aSize);
111   nsresult NotifyPainted(void);
112   nsresult GetIsOOP(bool* aIsOOP);
113   nsresult SetBackgroundUnknown();
114   nsresult BeginUpdateBackground(nsIntRect* aRect, DrawTarget** aContext);
115   nsresult EndUpdateBackground(nsIntRect* aRect);
116   nsresult IsTransparent(bool* isTransparent);
117   nsresult GetFormValue(nsAString& aValue);
118   nsresult PushPopupsEnabledState(bool aEnabled);
119   nsresult PopPopupsEnabledState();
120   nsresult GetPluginAPIVersion(uint16_t* version);
121   nsresult InvalidateRect(NPRect *invalidRect);
122   nsresult InvalidateRegion(NPRegion invalidRegion);
123   nsresult GetMIMEType(const char* *result);
124 #if defined(XP_WIN)
125   nsresult GetScrollCaptureContainer(mozilla::layers::ImageContainer **aContainer);
126 #endif
127   nsresult HandledWindowedPluginKeyEvent(
128              const mozilla::NativeEventData& aKeyEventData,
129              bool aIsConsumed);
130   nsPluginInstanceOwner* GetOwner();
131   void SetOwner(nsPluginInstanceOwner *aOwner);
132   void DidComposite();
133 
HasAudioChannelAgent()134   bool HasAudioChannelAgent() const
135   {
136     return !!mAudioChannelAgent;
137   }
138 
139   nsresult GetOrCreateAudioChannelAgent(nsIAudioChannelAgent** aAgent);
140 
141   nsresult SetMuted(bool aIsMuted);
142 
143   nsNPAPIPlugin* GetPlugin();
144 
145   nsresult GetNPP(NPP * aNPP);
146 
147   NPError SetWindowless(bool aWindowless);
148 
149   NPError SetTransparent(bool aTransparent);
150 
151   NPError SetWantsAllNetworkStreams(bool aWantsAllNetworkStreams);
152 
153   NPError SetUsesDOMForCursor(bool aUsesDOMForCursor);
154   bool UsesDOMForCursor();
155 
156   void SetDrawingModel(NPDrawingModel aModel);
157   void RedrawPlugin();
158 #ifdef XP_MACOSX
159   void SetEventModel(NPEventModel aModel);
160 
GetCurrentEvent()161   void* GetCurrentEvent() {
162     return mCurrentPluginEvent;
163   }
164 #endif
165 
166 #ifdef MOZ_WIDGET_ANDROID
167   void NotifyForeground(bool aForeground);
168   void NotifyOnScreen(bool aOnScreen);
169   void MemoryPressure();
170   void NotifyFullScreen(bool aFullScreen);
171   void NotifySize(nsIntSize size);
172 
CurrentSize()173   nsIntSize CurrentSize() { return mCurrentSize; }
174 
IsOnScreen()175   bool IsOnScreen() {
176     return mOnScreen;
177   }
178 
GetANPDrawingModel()179   uint32_t GetANPDrawingModel() { return mANPDrawingModel; }
180   void SetANPDrawingModel(uint32_t aModel);
181 
182   void* GetJavaSurface();
183 
184   void PostEvent(void* event);
185 
186   // These are really mozilla::dom::ScreenOrientation, but it's
187   // difficult to include that here
FullScreenOrientation()188   uint32_t FullScreenOrientation() { return mFullScreenOrientation; }
189   void SetFullScreenOrientation(uint32_t orientation);
190 
191   void SetWakeLock(bool aLock);
192 
193   mozilla::gl::GLContext* GLContext();
194 
195   // For ANPOpenGL
196   class TextureInfo {
197   public:
TextureInfo()198     TextureInfo() :
199       mTexture(0), mWidth(0), mHeight(0), mInternalFormat(0)
200     {
201     }
202 
TextureInfo(GLuint aTexture,int32_t aWidth,int32_t aHeight,GLuint aInternalFormat)203     TextureInfo(GLuint aTexture, int32_t aWidth, int32_t aHeight, GLuint aInternalFormat) :
204       mTexture(aTexture), mWidth(aWidth), mHeight(aHeight), mInternalFormat(aInternalFormat)
205     {
206     }
207 
208     GLuint mTexture;
209     int32_t mWidth;
210     int32_t mHeight;
211     GLuint mInternalFormat;
212   };
213 
214   // For ANPNativeWindow
215   void* AcquireContentWindow();
216 
217   mozilla::gl::AndroidSurfaceTexture* AsSurfaceTexture();
218 
219   // For ANPVideo
220   class VideoInfo {
221   public:
VideoInfo(mozilla::gl::AndroidSurfaceTexture * aSurfaceTexture)222     VideoInfo(mozilla::gl::AndroidSurfaceTexture* aSurfaceTexture) :
223       mSurfaceTexture(aSurfaceTexture)
224     {
225     }
226 
~VideoInfo()227     ~VideoInfo()
228     {
229       mSurfaceTexture = nullptr;
230     }
231 
232     RefPtr<mozilla::gl::AndroidSurfaceTexture> mSurfaceTexture;
233     gfxRect mDimensions;
234   };
235 
236   void* AcquireVideoWindow();
237   void ReleaseVideoWindow(void* aWindow);
238   void SetVideoDimensions(void* aWindow, gfxRect aDimensions);
239 
240   void GetVideos(nsTArray<VideoInfo*>& aVideos);
241 
SetOriginPos(mozilla::gl::OriginPos aOriginPos)242   void SetOriginPos(mozilla::gl::OriginPos aOriginPos) {
243     mOriginPos = aOriginPos;
244   }
OriginPos()245   mozilla::gl::OriginPos OriginPos() const { return mOriginPos; }
246 
247   static nsNPAPIPluginInstance* GetFromNPP(NPP npp);
248 #endif
249 
250   nsresult NewStreamListener(const char* aURL, void* notifyData,
251                              nsNPAPIPluginStreamListener** listener);
252 
253   nsNPAPIPluginInstance();
254 
255   // To be called when an instance becomes orphaned, when
256   // it's plugin is no longer guaranteed to be around.
257   void Destroy();
258 
259   // Indicates whether the plugin is running normally.
IsRunning()260   bool IsRunning() {
261     return RUNNING == mRunning;
262   }
HasStartedDestroying()263   bool HasStartedDestroying() {
264     return mRunning >= DESTROYING;
265   }
266 
267   // Indicates whether the plugin is running normally or being shut down
CanFireNotifications()268   bool CanFireNotifications() {
269     return mRunning == RUNNING || mRunning == DESTROYING;
270   }
271 
272   // return is only valid when the plugin is not running
273   mozilla::TimeStamp StopTime();
274 
275   // cache this NPAPI plugin
276   void SetCached(bool aCache);
277 
278   already_AddRefed<nsPIDOMWindowOuter> GetDOMWindow();
279 
280   nsresult PrivateModeStateChanged(bool aEnabled);
281 
282   nsresult IsPrivateBrowsing(bool *aEnabled);
283 
284   nsresult GetDOMElement(nsIDOMElement* *result);
285 
286   nsNPAPITimer* TimerWithID(uint32_t id, uint32_t* index);
287   uint32_t      ScheduleTimer(uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
288   void          UnscheduleTimer(uint32_t timerID);
289   NPBool        ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
290 
291 
292   nsTArray<nsNPAPIPluginStreamListener*> *StreamListeners();
293 
294   nsTArray<nsPluginStreamListenerPeer*> *FileCachedStreamListeners();
295 
296   nsresult AsyncSetWindow(NPWindow& window);
297 
298   void URLRedirectResponse(void* notifyData, NPBool allow);
299 
300   NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
301                            void *initData, NPAsyncSurface *surface);
302   NPError FinalizeAsyncSurface(NPAsyncSurface *surface);
303   void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed);
304 
305   // Called when the instance fails to instantiate beceause the Carbon
306   // event model is not supported.
307   void CarbonNPAPIFailure();
308 
309   // Returns the contents scale factor of the screen the plugin is drawn on.
310   double GetContentsScaleFactor();
311 
312   // Returns the css zoom factor of the document the plugin is drawn on.
313   float GetCSSZoomFactor();
314 
315   nsresult GetRunID(uint32_t *aRunID);
316 
InPluginCallUnsafeForReentry()317   static bool InPluginCallUnsafeForReentry() { return gInUnsafePluginCalls > 0; }
BeginPluginCall(NSPluginCallReentry aReentryState)318   static void BeginPluginCall(NSPluginCallReentry aReentryState)
319   {
320     if (aReentryState == NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO) {
321       ++gInUnsafePluginCalls;
322     }
323   }
EndPluginCall(NSPluginCallReentry aReentryState)324   static void EndPluginCall(NSPluginCallReentry aReentryState)
325   {
326     if (aReentryState == NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO) {
327       NS_ASSERTION(gInUnsafePluginCalls > 0, "Must be in plugin call");
328       --gInUnsafePluginCalls;
329     }
330   }
331 
332 protected:
333 
334   virtual ~nsNPAPIPluginInstance();
335 
336   nsresult GetTagType(nsPluginTagType *result);
337   nsresult GetMode(int32_t *result);
338 
339   // check if this is a Java applet and affected by bug 750480
340   void CheckJavaC2PJSObjectQuirk(uint16_t paramCount,
341                                  const char* const* names,
342                                  const char* const* values);
343 
344   // The structure used to communicate between the plugin instance and
345   // the browser.
346   NPP_t mNPP;
347 
348   NPDrawingModel mDrawingModel;
349 
350 #ifdef MOZ_WIDGET_ANDROID
351   uint32_t mANPDrawingModel;
352 
353   friend class PluginEventRunnable;
354 
355   nsTArray<RefPtr<PluginEventRunnable>> mPostedEvents;
356   void PopPostedEvent(PluginEventRunnable* r);
357   void OnSurfaceTextureFrameAvailable();
358 
359   uint32_t mFullScreenOrientation;
360   bool mWakeLocked;
361   bool mFullScreen;
362   mozilla::gl::OriginPos mOriginPos;
363 
364   RefPtr<mozilla::gl::AndroidSurfaceTexture> mContentSurface;
365 #endif
366 
367   enum {
368     NOT_STARTED,
369     RUNNING,
370     DESTROYING,
371     DESTROYED
372   } mRunning;
373 
374   // these are used to store the windowless properties
375   // which the browser will later query
376   bool mWindowless;
377   bool mTransparent;
378   bool mCached;
379   bool mUsesDOMForCursor;
380 
381 public:
382   // True while creating the plugin, or calling NPP_SetWindow() on it.
383   bool mInPluginInitCall;
384 
385   nsXPIDLCString mFakeURL;
386 
387 private:
388   RefPtr<nsNPAPIPlugin> mPlugin;
389 
390   nsTArray<nsNPAPIPluginStreamListener*> mStreamListeners;
391 
392   nsTArray<nsPluginStreamListenerPeer*> mFileCachedStreamListeners;
393 
394   nsTArray<PopupControlState> mPopupStates;
395 
396   char* mMIMEType;
397 
398   // Weak pointer to the owner. The owner nulls this out (by calling
399   // InvalidateOwner()) when it's no longer our owner.
400   nsPluginInstanceOwner *mOwner;
401 
402   nsTArray<nsNPAPITimer*> mTimers;
403 
404 #ifdef XP_MACOSX
405   // non-null during a HandleEvent call
406   void* mCurrentPluginEvent;
407 #endif
408 
409   // Timestamp for the last time this plugin was stopped.
410   // This is only valid when the plugin is actually stopped!
411   mozilla::TimeStamp mStopTime;
412 
413 #ifdef MOZ_WIDGET_ANDROID
414   already_AddRefed<mozilla::gl::AndroidSurfaceTexture> CreateSurfaceTexture();
415 
416   std::map<void*, VideoInfo*> mVideos;
417   bool mOnScreen;
418 
419   nsIntSize mCurrentSize;
420 #endif
421 
422   // is this instance Java and affected by bug 750480?
423   bool mHaveJavaC2PJSObjectQuirk;
424 
425   static uint32_t gInUnsafePluginCalls;
426 
427   // The arrays can only be released when the plugin instance is destroyed,
428   // because the plugin, in in-process mode, might keep a reference to them.
429   uint32_t mCachedParamLength;
430   char **mCachedParamNames;
431   char **mCachedParamValues;
432 
433   nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
434   bool mMuted;
435 };
436 
437 // On Android, we need to guard against plugin code leaking entries in the local
438 // JNI ref table. See https://bugzilla.mozilla.org/show_bug.cgi?id=780831#c21
439 #ifdef MOZ_WIDGET_ANDROID
440   #define MAIN_THREAD_JNI_REF_GUARD mozilla::AutoLocalJNIFrame jniFrame
441 #else
442   #define MAIN_THREAD_JNI_REF_GUARD
443 #endif
444 
445 void NS_NotifyBeginPluginCall(NSPluginCallReentry aReentryState);
446 void NS_NotifyPluginCall(NSPluginCallReentry aReentryState);
447 
448 #define NS_TRY_SAFE_CALL_RETURN(ret, fun, pluginInst, pluginCallReentry) \
449 PR_BEGIN_MACRO                                     \
450   MAIN_THREAD_JNI_REF_GUARD;                       \
451   NS_NotifyBeginPluginCall(pluginCallReentry); \
452   ret = fun;                                       \
453   NS_NotifyPluginCall(pluginCallReentry); \
454 PR_END_MACRO
455 
456 #define NS_TRY_SAFE_CALL_VOID(fun, pluginInst, pluginCallReentry) \
457 PR_BEGIN_MACRO                                     \
458   MAIN_THREAD_JNI_REF_GUARD;                       \
459   NS_NotifyBeginPluginCall(pluginCallReentry); \
460   fun;                                             \
461   NS_NotifyPluginCall(pluginCallReentry); \
462 PR_END_MACRO
463 
464 #endif // nsNPAPIPluginInstance_h_
465