1 /*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "NPJSObject.h"
28
29 #include "JSNPObject.h"
30 #include "NPRuntimeObjectMap.h"
31 #include "NPRuntimeUtilities.h"
32 #include "PluginView.h"
33 #include <JavaScriptCore/JSLock.h>
34 #include <JavaScriptCore/JSObject.h>
35 #include <WebCore/Frame.h>
36 #include <WebCore/IdentifierRep.h>
37 #include <WebCore/NotImplemented.h>
38 #include <wtf/text/WTFString.h>
39
40 using namespace JSC;
41 using namespace WebCore;
42
43 namespace WebKit {
44
create(JSGlobalData & globalData,NPRuntimeObjectMap * objectMap,JSObject * jsObject)45 NPJSObject* NPJSObject::create(JSGlobalData& globalData, NPRuntimeObjectMap* objectMap, JSObject* jsObject)
46 {
47 // We should never have a JSNPObject inside an NPJSObject.
48 ASSERT(!jsObject->inherits(&JSNPObject::s_info));
49
50 NPJSObject* npJSObject = toNPJSObject(createNPObject(0, npClass()));
51 npJSObject->initialize(globalData, objectMap, jsObject);
52
53 return npJSObject;
54 }
55
NPJSObject()56 NPJSObject::NPJSObject()
57 : m_objectMap(0)
58 {
59 }
60
~NPJSObject()61 NPJSObject::~NPJSObject()
62 {
63 m_objectMap->npJSObjectDestroyed(this);
64 }
65
isNPJSObject(NPObject * npObject)66 bool NPJSObject::isNPJSObject(NPObject* npObject)
67 {
68 return npObject->_class == npClass();
69 }
70
initialize(JSGlobalData & globalData,NPRuntimeObjectMap * objectMap,JSObject * jsObject)71 void NPJSObject::initialize(JSGlobalData& globalData, NPRuntimeObjectMap* objectMap, JSObject* jsObject)
72 {
73 ASSERT(!m_objectMap);
74 ASSERT(!m_jsObject);
75
76 m_objectMap = objectMap;
77 m_jsObject.set(globalData, jsObject);
78 }
79
identifierFromIdentifierRep(ExecState * exec,IdentifierRep * identifierRep)80 static Identifier identifierFromIdentifierRep(ExecState* exec, IdentifierRep* identifierRep)
81 {
82 ASSERT(identifierRep->isString());
83
84 const char* string = identifierRep->string();
85 int length = strlen(string);
86
87 return Identifier(exec, String::fromUTF8WithLatin1Fallback(string, length).impl());
88 }
89
hasMethod(NPIdentifier methodName)90 bool NPJSObject::hasMethod(NPIdentifier methodName)
91 {
92 IdentifierRep* identifierRep = static_cast<IdentifierRep*>(methodName);
93
94 if (!identifierRep->isString())
95 return false;
96
97 ExecState* exec = m_objectMap->globalExec();
98 if (!exec)
99 return false;
100
101 JSLock lock(SilenceAssertionsOnly);
102
103 JSValue value = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
104 exec->clearException();
105
106 CallData callData;
107 return getCallData(value, callData) != CallTypeNone;
108 }
109
invoke(NPIdentifier methodName,const NPVariant * arguments,uint32_t argumentCount,NPVariant * result)110 bool NPJSObject::invoke(NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
111 {
112 IdentifierRep* identifierRep = static_cast<IdentifierRep*>(methodName);
113
114 if (!identifierRep->isString())
115 return false;
116
117 ExecState* exec = m_objectMap->globalExec();
118 if (!exec)
119 return false;
120
121 JSLock lock(SilenceAssertionsOnly);
122
123 JSValue function = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
124 return invoke(exec, m_objectMap->globalObject(), function, arguments, argumentCount, result);
125 }
126
invokeDefault(const NPVariant * arguments,uint32_t argumentCount,NPVariant * result)127 bool NPJSObject::invokeDefault(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
128 {
129 ExecState* exec = m_objectMap->globalExec();
130 if (!exec)
131 return false;
132
133 JSLock lock(SilenceAssertionsOnly);
134
135 JSValue function = m_jsObject.get();
136 return invoke(exec, m_objectMap->globalObject(), function, arguments, argumentCount, result);
137 }
138
hasProperty(NPIdentifier identifier)139 bool NPJSObject::hasProperty(NPIdentifier identifier)
140 {
141 IdentifierRep* identifierRep = static_cast<IdentifierRep*>(identifier);
142
143 ExecState* exec = m_objectMap->globalExec();
144 if (!exec)
145 return false;
146
147 JSLock lock(SilenceAssertionsOnly);
148
149 bool result;
150 if (identifierRep->isString())
151 result = m_jsObject->hasProperty(exec, identifierFromIdentifierRep(exec, identifierRep));
152 else
153 result = m_jsObject->hasProperty(exec, identifierRep->number());
154
155 exec->clearException();
156 return result;
157 }
158
getProperty(NPIdentifier propertyName,NPVariant * result)159 bool NPJSObject::getProperty(NPIdentifier propertyName, NPVariant* result)
160 {
161 IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
162
163 ExecState* exec = m_objectMap->globalExec();
164 if (!exec)
165 return false;
166
167 JSLock lock(SilenceAssertionsOnly);
168 JSValue jsResult;
169 if (identifierRep->isString())
170 jsResult = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
171 else
172 jsResult = m_jsObject->get(exec, identifierRep->number());
173
174 m_objectMap->convertJSValueToNPVariant(exec, jsResult, *result);
175 exec->clearException();
176 return true;
177 }
178
setProperty(NPIdentifier propertyName,const NPVariant * value)179 bool NPJSObject::setProperty(NPIdentifier propertyName, const NPVariant* value)
180 {
181 IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
182
183 ExecState* exec = m_objectMap->globalExec();
184 if (!exec)
185 return false;
186
187 JSLock lock(SilenceAssertionsOnly);
188
189 JSValue jsValue = m_objectMap->convertNPVariantToJSValue(exec, m_objectMap->globalObject(), *value);
190 if (identifierRep->isString()) {
191 PutPropertySlot slot;
192 m_jsObject->put(exec, identifierFromIdentifierRep(exec, identifierRep), jsValue, slot);
193 } else
194 m_jsObject->put(exec, identifierRep->number(), jsValue);
195 exec->clearException();
196
197 return true;
198 }
199
removeProperty(NPIdentifier propertyName)200 bool NPJSObject::removeProperty(NPIdentifier propertyName)
201 {
202 IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
203
204 ExecState* exec = m_objectMap->globalExec();
205 if (!exec)
206 return false;
207
208 JSLock lock(SilenceAssertionsOnly);
209 if (identifierRep->isString()) {
210 Identifier identifier = identifierFromIdentifierRep(exec, identifierRep);
211
212 if (!m_jsObject->hasProperty(exec, identifier)) {
213 exec->clearException();
214 return false;
215 }
216
217 m_jsObject->deleteProperty(exec, identifier);
218 } else {
219 if (!m_jsObject->hasProperty(exec, identifierRep->number())) {
220 exec->clearException();
221 return false;
222 }
223
224 m_jsObject->deleteProperty(exec, identifierRep->number());
225 }
226
227 exec->clearException();
228 return true;
229 }
230
enumerate(NPIdentifier ** identifiers,uint32_t * identifierCount)231 bool NPJSObject::enumerate(NPIdentifier** identifiers, uint32_t* identifierCount)
232 {
233 ExecState* exec = m_objectMap->globalExec();
234 if (!exec)
235 return false;
236
237 JSLock lock(SilenceAssertionsOnly);
238
239 PropertyNameArray propertyNames(exec);
240 m_jsObject->getPropertyNames(exec, propertyNames);
241
242 NPIdentifier* nameIdentifiers = npnMemNewArray<NPIdentifier>(propertyNames.size());
243
244 for (size_t i = 0; i < propertyNames.size(); ++i)
245 nameIdentifiers[i] = static_cast<NPIdentifier>(IdentifierRep::get(propertyNames[i].ustring().utf8().data()));
246
247 *identifiers = nameIdentifiers;
248 *identifierCount = propertyNames.size();
249
250 return true;
251 }
252
construct(const NPVariant * arguments,uint32_t argumentCount,NPVariant * result)253 bool NPJSObject::construct(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
254 {
255 ExecState* exec = m_objectMap->globalExec();
256 if (!exec)
257 return false;
258
259 JSLock lock(SilenceAssertionsOnly);
260
261 ConstructData constructData;
262 ConstructType constructType = getConstructData(m_jsObject.get(), constructData);
263 if (constructType == ConstructTypeNone)
264 return false;
265
266 // Convert the passed in arguments.
267 MarkedArgumentBuffer argumentList;
268 for (uint32_t i = 0; i < argumentCount; ++i)
269 argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, m_objectMap->globalObject(), arguments[i]));
270
271 exec->globalData().timeoutChecker.start();
272 JSValue value = JSC::construct(exec, m_jsObject.get(), constructType, constructData, argumentList);
273 exec->globalData().timeoutChecker.stop();
274
275 // Convert and return the new object.
276 m_objectMap->convertJSValueToNPVariant(exec, value, *result);
277 exec->clearException();
278
279 return true;
280 }
281
invoke(ExecState * exec,JSGlobalObject * globalObject,JSValue function,const NPVariant * arguments,uint32_t argumentCount,NPVariant * result)282 bool NPJSObject::invoke(ExecState* exec, JSGlobalObject* globalObject, JSValue function, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
283 {
284 CallData callData;
285 CallType callType = getCallData(function, callData);
286 if (callType == CallTypeNone)
287 return false;
288
289 // Convert the passed in arguments.
290 MarkedArgumentBuffer argumentList;
291 for (uint32_t i = 0; i < argumentCount; ++i)
292 argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, globalObject, arguments[i]));
293
294 exec->globalData().timeoutChecker.start();
295 JSValue value = JSC::call(exec, function, callType, callData, m_jsObject.get(), argumentList);
296 exec->globalData().timeoutChecker.stop();
297
298 // Convert and return the result of the function call.
299 m_objectMap->convertJSValueToNPVariant(exec, value, *result);
300 exec->clearException();
301
302 return true;
303 }
304
npClass()305 NPClass* NPJSObject::npClass()
306 {
307 static NPClass npClass = {
308 NP_CLASS_STRUCT_VERSION,
309 NP_Allocate,
310 NP_Deallocate,
311 0,
312 NP_HasMethod,
313 NP_Invoke,
314 NP_InvokeDefault,
315 NP_HasProperty,
316 NP_GetProperty,
317 NP_SetProperty,
318 NP_RemoveProperty,
319 NP_Enumerate,
320 NP_Construct
321 };
322
323 return &npClass;
324 }
325
NP_Allocate(NPP npp,NPClass *)326 NPObject* NPJSObject::NP_Allocate(NPP npp, NPClass*)
327 {
328 ASSERT_UNUSED(npp, !npp);
329
330 return new NPJSObject;
331 }
332
NP_Deallocate(NPObject * npObject)333 void NPJSObject::NP_Deallocate(NPObject* npObject)
334 {
335 NPJSObject* npJSObject = toNPJSObject(npObject);
336 delete npJSObject;
337 }
338
NP_HasMethod(NPObject * npObject,NPIdentifier methodName)339 bool NPJSObject::NP_HasMethod(NPObject* npObject, NPIdentifier methodName)
340 {
341 return toNPJSObject(npObject)->hasMethod(methodName);
342 }
343
NP_Invoke(NPObject * npObject,NPIdentifier methodName,const NPVariant * arguments,uint32_t argumentCount,NPVariant * result)344 bool NPJSObject::NP_Invoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
345 {
346 return toNPJSObject(npObject)->invoke(methodName, arguments, argumentCount, result);
347 }
348
NP_InvokeDefault(NPObject * npObject,const NPVariant * arguments,uint32_t argumentCount,NPVariant * result)349 bool NPJSObject::NP_InvokeDefault(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
350 {
351 return toNPJSObject(npObject)->invokeDefault(arguments, argumentCount, result);
352 }
353
NP_HasProperty(NPObject * npObject,NPIdentifier propertyName)354 bool NPJSObject::NP_HasProperty(NPObject* npObject, NPIdentifier propertyName)
355 {
356 return toNPJSObject(npObject)->hasProperty(propertyName);
357 }
358
NP_GetProperty(NPObject * npObject,NPIdentifier propertyName,NPVariant * result)359 bool NPJSObject::NP_GetProperty(NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
360 {
361 return toNPJSObject(npObject)->getProperty(propertyName, result);
362 }
363
NP_SetProperty(NPObject * npObject,NPIdentifier propertyName,const NPVariant * value)364 bool NPJSObject::NP_SetProperty(NPObject* npObject, NPIdentifier propertyName, const NPVariant* value)
365 {
366 return toNPJSObject(npObject)->setProperty(propertyName, value);
367 }
368
NP_RemoveProperty(NPObject * npObject,NPIdentifier propertyName)369 bool NPJSObject::NP_RemoveProperty(NPObject* npObject, NPIdentifier propertyName)
370 {
371 return toNPJSObject(npObject)->removeProperty(propertyName);
372 }
373
NP_Enumerate(NPObject * npObject,NPIdentifier ** identifiers,uint32_t * identifierCount)374 bool NPJSObject::NP_Enumerate(NPObject* npObject, NPIdentifier** identifiers, uint32_t* identifierCount)
375 {
376 return toNPJSObject(npObject)->enumerate(identifiers, identifierCount);
377 }
378
NP_Construct(NPObject * npObject,const NPVariant * arguments,uint32_t argumentCount,NPVariant * result)379 bool NPJSObject::NP_Construct(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
380 {
381 return toNPJSObject(npObject)->construct(arguments, argumentCount, result);
382 }
383
384 } // namespace WebKit
385