1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: sw=2 ts=2 et :
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef dom_plugins_PluginScriptableObjectUtils_h
8 #define dom_plugins_PluginScriptableObjectUtils_h
9 
10 #include "PluginModuleParent.h"
11 #include "PluginModuleChild.h"
12 #include "PluginInstanceParent.h"
13 #include "PluginInstanceChild.h"
14 #include "PluginScriptableObjectParent.h"
15 #include "PluginScriptableObjectChild.h"
16 
17 #include "npapi.h"
18 #include "npfunctions.h"
19 #include "npruntime.h"
20 
21 #include "nsDebug.h"
22 
23 namespace mozilla {
24 namespace plugins {
25 
GetInstance(NPObject * aObject)26 inline PluginInstanceParent* GetInstance(NPObject* aObject) {
27   NS_ASSERTION(aObject->_class == PluginScriptableObjectParent::GetClass(),
28                "Bad class!");
29 
30   ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
31   if (object->invalidated) {
32     NS_WARNING("Calling method on an invalidated object!");
33     return nullptr;
34   }
35   if (!object->parent) {
36     return nullptr;
37   }
38   return object->parent->GetInstance();
39 }
40 
NPObjectFromVariant(const Variant & aRemoteVariant)41 inline NPObject* NPObjectFromVariant(const Variant& aRemoteVariant) {
42   switch (aRemoteVariant.type()) {
43     case Variant::TPPluginScriptableObjectParent: {
44       PluginScriptableObjectParent* actor =
45           const_cast<PluginScriptableObjectParent*>(
46               reinterpret_cast<const PluginScriptableObjectParent*>(
47                   aRemoteVariant.get_PPluginScriptableObjectParent()));
48       return actor->GetObject(true);
49     }
50 
51     case Variant::TPPluginScriptableObjectChild: {
52       PluginScriptableObjectChild* actor =
53           const_cast<PluginScriptableObjectChild*>(
54               reinterpret_cast<const PluginScriptableObjectChild*>(
55                   aRemoteVariant.get_PPluginScriptableObjectChild()));
56       return actor->GetObject(true);
57     }
58 
59     default:
60       MOZ_ASSERT_UNREACHABLE("Shouldn't get here!");
61       return nullptr;
62   }
63 }
64 
NPObjectFromVariant(const NPVariant & aVariant)65 inline NPObject* NPObjectFromVariant(const NPVariant& aVariant) {
66   NS_ASSERTION(NPVARIANT_IS_OBJECT(aVariant), "Wrong variant type!");
67   return NPVARIANT_TO_OBJECT(aVariant);
68 }
69 
GetNetscapeFuncs(PluginInstanceParent * aInstance)70 inline const NPNetscapeFuncs* GetNetscapeFuncs(
71     PluginInstanceParent* aInstance) {
72   PluginModuleParent* module = aInstance->Module();
73   if (!module) {
74     NS_WARNING("Null module?!");
75     return nullptr;
76   }
77   return module->GetNetscapeFuncs();
78 }
79 
GetNetscapeFuncs(NPObject * aObject)80 inline const NPNetscapeFuncs* GetNetscapeFuncs(NPObject* aObject) {
81   NS_ASSERTION(aObject->_class == PluginScriptableObjectParent::GetClass(),
82                "Bad class!");
83 
84   PluginInstanceParent* instance = GetInstance(aObject);
85   if (!instance) {
86     return nullptr;
87   }
88 
89   return GetNetscapeFuncs(instance);
90 }
91 
ReleaseRemoteVariant(Variant & aVariant)92 inline void ReleaseRemoteVariant(Variant& aVariant) {
93   switch (aVariant.type()) {
94     case Variant::TPPluginScriptableObjectParent: {
95       PluginScriptableObjectParent* actor =
96           const_cast<PluginScriptableObjectParent*>(
97               reinterpret_cast<const PluginScriptableObjectParent*>(
98                   aVariant.get_PPluginScriptableObjectParent()));
99       actor->Unprotect();
100       break;
101     }
102 
103     case Variant::TPPluginScriptableObjectChild: {
104       NS_ASSERTION(XRE_GetProcessType() == GeckoProcessType_Plugin,
105                    "Should only be running in the child!");
106       PluginScriptableObjectChild* actor =
107           const_cast<PluginScriptableObjectChild*>(
108               reinterpret_cast<const PluginScriptableObjectChild*>(
109                   aVariant.get_PPluginScriptableObjectChild()));
110       actor->Unprotect();
111       break;
112     }
113 
114     default:
115       break;  // Intentional fall-through for other variant types.
116   }
117 
118   aVariant = mozilla::void_t();
119 }
120 
121 bool ConvertToVariant(const Variant& aRemoteVariant, NPVariant& aVariant,
122                       PluginInstanceParent* aInstance = nullptr);
123 
124 template <class InstanceType>
125 bool ConvertToRemoteVariant(const NPVariant& aVariant, Variant& aRemoteVariant,
126                             InstanceType* aInstance,
127                             bool aProtectActors = false);
128 
129 class ProtectedVariant {
130  public:
ProtectedVariant(const NPVariant & aVariant,PluginInstanceParent * aInstance)131   ProtectedVariant(const NPVariant& aVariant, PluginInstanceParent* aInstance) {
132     mOk = ConvertToRemoteVariant(aVariant, mVariant, aInstance, true);
133   }
134 
ProtectedVariant(const NPVariant & aVariant,PluginInstanceChild * aInstance)135   ProtectedVariant(const NPVariant& aVariant, PluginInstanceChild* aInstance) {
136     mOk = ConvertToRemoteVariant(aVariant, mVariant, aInstance, true);
137   }
138 
~ProtectedVariant()139   ~ProtectedVariant() { ReleaseRemoteVariant(mVariant); }
140 
IsOk()141   bool IsOk() { return mOk; }
142 
143   operator const Variant&() { return mVariant; }
144 
145  private:
146   Variant mVariant;
147   bool mOk;
148 };
149 
150 class ProtectedVariantArray {
151  public:
ProtectedVariantArray(const NPVariant * aArgs,uint32_t aCount,PluginInstanceParent * aInstance)152   ProtectedVariantArray(const NPVariant* aArgs, uint32_t aCount,
153                         PluginInstanceParent* aInstance)
154       : mUsingShadowArray(false) {
155     for (uint32_t index = 0; index < aCount; index++) {
156       Variant* remoteVariant = mArray.AppendElement();
157       if (!(remoteVariant &&
158             ConvertToRemoteVariant(aArgs[index], *remoteVariant, aInstance,
159                                    true))) {
160         mOk = false;
161         return;
162       }
163     }
164     mOk = true;
165   }
166 
ProtectedVariantArray(const NPVariant * aArgs,uint32_t aCount,PluginInstanceChild * aInstance)167   ProtectedVariantArray(const NPVariant* aArgs, uint32_t aCount,
168                         PluginInstanceChild* aInstance)
169       : mUsingShadowArray(false) {
170     for (uint32_t index = 0; index < aCount; index++) {
171       Variant* remoteVariant = mArray.AppendElement();
172       if (!(remoteVariant &&
173             ConvertToRemoteVariant(aArgs[index], *remoteVariant, aInstance,
174                                    true))) {
175         mOk = false;
176         return;
177       }
178     }
179     mOk = true;
180   }
181 
~ProtectedVariantArray()182   ~ProtectedVariantArray() {
183     nsTArray<Variant>& vars = EnsureAndGetShadowArray();
184     uint32_t count = vars.Length();
185     for (uint32_t index = 0; index < count; index++) {
186       ReleaseRemoteVariant(vars[index]);
187     }
188   }
189 
190   operator const nsTArray<Variant>&() { return EnsureAndGetShadowArray(); }
191 
IsOk()192   bool IsOk() { return mOk; }
193 
194  private:
EnsureAndGetShadowArray()195   nsTArray<Variant>& EnsureAndGetShadowArray() {
196     if (!mUsingShadowArray) {
197       mShadowArray.SwapElements(mArray);
198       mUsingShadowArray = true;
199     }
200     return mShadowArray;
201   }
202 
203   // We convert the variants fallibly, but pass them to Call*()
204   // methods as an infallible array
205   nsTArray<Variant> mArray;
206   nsTArray<Variant> mShadowArray;
207   bool mOk;
208   bool mUsingShadowArray;
209 };
210 
211 template <class ActorType>
212 struct ProtectedActorTraits {
213   static bool Nullable();
214 };
215 
216 template <class ActorType, class Traits = ProtectedActorTraits<ActorType> >
217 class ProtectedActor {
218  public:
ProtectedActor(ActorType * aActor)219   explicit ProtectedActor(ActorType* aActor) : mActor(aActor) {
220     if (!Traits::Nullable()) {
221       NS_ASSERTION(mActor, "This should never be null!");
222     }
223   }
224 
~ProtectedActor()225   ~ProtectedActor() {
226     if (Traits::Nullable() && !mActor) return;
227     mActor->Unprotect();
228   }
229 
230   ActorType* operator->() { return mActor; }
231 
232   explicit operator bool() { return !!mActor; }
233 
234  private:
235   ActorType* mActor;
236 };
237 
238 template <>
239 struct ProtectedActorTraits<PluginScriptableObjectParent> {
240   static bool Nullable() { return true; }
241 };
242 
243 template <>
244 struct ProtectedActorTraits<PluginScriptableObjectChild> {
245   static bool Nullable() { return false; }
246 };
247 
248 } /* namespace plugins */
249 } /* namespace mozilla */
250 
251 #include "PluginScriptableObjectUtils-inl.h"
252 
253 #endif /* dom_plugins_PluginScriptableObjectUtils_h */
254