NPJSObject.cpp revision 65f03d4f644ce73618e5f4f50dd694b26f55ae12
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 "NPJSObject.h"
27
28#include "JSNPObject.h"
29#include "NPRuntimeObjectMap.h"
30#include "NPRuntimeUtilities.h"
31#include "NotImplemented.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 <wtf/text/WTFString.h>
38
39using namespace JSC;
40using namespace WebCore;
41
42namespace WebKit {
43
44NPJSObject* NPJSObject::create(NPRuntimeObjectMap* objectMap, JSObject* jsObject)
45{
46    // We should never have a JSNPObject inside an NPJSObject.
47    ASSERT(!jsObject->inherits(&JSNPObject::s_info));
48
49    NPJSObject* npJSObject = toNPJSObject(createNPObject(0, npClass()));
50    npJSObject->initialize(objectMap, jsObject);
51
52    return npJSObject;
53}
54
55NPJSObject::NPJSObject()
56    : m_objectMap(0)
57{
58}
59
60NPJSObject::~NPJSObject()
61{
62    m_objectMap->npJSObjectDestroyed(this);
63}
64
65bool NPJSObject::isNPJSObject(NPObject* npObject)
66{
67    return npObject->_class == npClass();
68}
69
70void NPJSObject::initialize(NPRuntimeObjectMap* objectMap, JSObject* jsObject)
71{
72    ASSERT(!m_objectMap);
73    ASSERT(!m_jsObject);
74
75    m_objectMap = objectMap;
76    m_jsObject = jsObject;
77}
78
79static Identifier identifierFromIdentifierRep(ExecState* exec, IdentifierRep* identifierRep)
80{
81    ASSERT(identifierRep->isString());
82
83    const char* string = identifierRep->string();
84    int length = strlen(string);
85
86    return Identifier(exec, String::fromUTF8WithLatin1Fallback(string, length).impl());
87}
88
89bool NPJSObject::hasMethod(NPIdentifier methodName)
90{
91    IdentifierRep* identifierRep = static_cast<IdentifierRep*>(methodName);
92
93    if (!identifierRep->isString())
94        return false;
95
96    ExecState* exec = m_objectMap->globalExec();
97    if (!exec)
98        return false;
99
100    JSLock lock(SilenceAssertionsOnly);
101
102    JSValue value = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
103    exec->clearException();
104
105    CallData callData;
106    return getCallData(value, callData) != CallTypeNone;
107}
108
109bool NPJSObject::invoke(NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
110{
111    IdentifierRep* identifierRep = static_cast<IdentifierRep*>(methodName);
112
113    if (!identifierRep->isString())
114        return false;
115
116    ExecState* exec = m_objectMap->globalExec();
117    if (!exec)
118        return false;
119
120    JSLock lock(SilenceAssertionsOnly);
121
122    JSValue function = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
123    return invoke(exec, m_objectMap->globalObject(), function, arguments, argumentCount, result);
124}
125
126bool NPJSObject::invokeDefault(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
127{
128    ExecState* exec = m_objectMap->globalExec();
129    if (!exec)
130        return false;
131
132    JSLock lock(SilenceAssertionsOnly);
133
134    JSValue function = m_jsObject;
135    return invoke(exec, m_objectMap->globalObject(), function, arguments, argumentCount, result);
136}
137
138bool NPJSObject::hasProperty(NPIdentifier identifier)
139{
140    IdentifierRep* identifierRep = static_cast<IdentifierRep*>(identifier);
141
142    ExecState* exec = m_objectMap->globalExec();
143    if (!exec)
144        return false;
145
146    JSLock lock(SilenceAssertionsOnly);
147
148    bool result;
149    if (identifierRep->isString())
150        result = m_jsObject->hasProperty(exec, identifierFromIdentifierRep(exec, identifierRep));
151    else
152        result = m_jsObject->hasProperty(exec, identifierRep->number());
153
154    exec->clearException();
155    return result;
156}
157
158bool NPJSObject::getProperty(NPIdentifier propertyName, NPVariant* result)
159{
160    IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
161
162    ExecState* exec = m_objectMap->globalExec();
163    if (!exec)
164        return false;
165
166    JSLock lock(SilenceAssertionsOnly);
167    JSValue jsResult;
168    if (identifierRep->isString())
169        jsResult = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
170    else
171        jsResult = m_jsObject->get(exec, identifierRep->number());
172
173    m_objectMap->convertJSValueToNPVariant(exec, jsResult, *result);
174    exec->clearException();
175    return true;
176}
177
178bool NPJSObject::setProperty(NPIdentifier propertyName, const NPVariant* value)
179{
180    IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
181
182    ExecState* exec = m_objectMap->globalExec();
183    if (!exec)
184        return false;
185
186    JSLock lock(SilenceAssertionsOnly);
187
188    JSValue jsValue = m_objectMap->convertNPVariantToJSValue(exec, m_objectMap->globalObject(), *value);
189    if (identifierRep->isString()) {
190        PutPropertySlot slot;
191        m_jsObject->put(exec, identifierFromIdentifierRep(exec, identifierRep), jsValue, slot);
192    } else
193        m_jsObject->put(exec, identifierRep->number(), jsValue);
194    exec->clearException();
195
196    return true;
197}
198
199bool NPJSObject::removeProperty(NPIdentifier propertyName)
200{
201    IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
202
203    ExecState* exec = m_objectMap->globalExec();
204    if (!exec)
205        return false;
206
207    JSLock lock(SilenceAssertionsOnly);
208    if (identifierRep->isString()) {
209        Identifier identifier = identifierFromIdentifierRep(exec, identifierRep);
210
211        if (!m_jsObject->hasProperty(exec, identifier)) {
212            exec->clearException();
213            return false;
214        }
215
216        m_jsObject->deleteProperty(exec, identifier);
217    } else {
218        if (!m_jsObject->hasProperty(exec, identifierRep->number())) {
219            exec->clearException();
220            return false;
221        }
222
223        m_jsObject->deleteProperty(exec, identifierRep->number());
224    }
225
226    exec->clearException();
227    return true;
228}
229
230bool NPJSObject::enumerate(NPIdentifier** identifiers, uint32_t* identifierCount)
231{
232    ExecState* exec = m_objectMap->globalExec();
233    if (!exec)
234        return false;
235
236    JSLock lock(SilenceAssertionsOnly);
237
238    PropertyNameArray propertyNames(exec);
239    m_jsObject->getPropertyNames(exec, propertyNames);
240
241    NPIdentifier* nameIdentifiers = npnMemNewArray<NPIdentifier>(propertyNames.size());
242
243    for (size_t i = 0; i < propertyNames.size(); ++i)
244        nameIdentifiers[i] = static_cast<NPIdentifier>(IdentifierRep::get(propertyNames[i].ustring().utf8().data()));
245
246    *identifiers = nameIdentifiers;
247    *identifierCount = propertyNames.size();
248
249    return true;
250}
251
252bool NPJSObject::construct(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
253{
254    ExecState* exec = m_objectMap->globalExec();
255    if (!exec)
256        return false;
257
258    JSLock lock(SilenceAssertionsOnly);
259
260    ConstructData constructData;
261    ConstructType constructType = getConstructData(m_jsObject, constructData);
262    if (constructType == ConstructTypeNone)
263        return false;
264
265    // Convert the passed in arguments.
266    MarkedArgumentBuffer argumentList;
267    for (uint32_t i = 0; i < argumentCount; ++i)
268        argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, m_objectMap->globalObject(), arguments[i]));
269
270    exec->globalData().timeoutChecker.start();
271    JSValue value = JSC::construct(exec, m_jsObject, constructType, constructData, argumentList);
272    exec->globalData().timeoutChecker.stop();
273
274    // Convert and return the new object.
275    m_objectMap->convertJSValueToNPVariant(exec, value, *result);
276    exec->clearException();
277
278    return true;
279}
280
281bool NPJSObject::invoke(ExecState* exec, JSGlobalObject* globalObject, JSValue function, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
282{
283    CallData callData;
284    CallType callType = getCallData(function, callData);
285    if (callType == CallTypeNone)
286        return false;
287
288    // Convert the passed in arguments.
289    MarkedArgumentBuffer argumentList;
290    for (uint32_t i = 0; i < argumentCount; ++i)
291        argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, globalObject, arguments[i]));
292
293    exec->globalData().timeoutChecker.start();
294    JSValue value = JSC::call(exec, function, callType, callData, m_jsObject, argumentList);
295    exec->globalData().timeoutChecker.stop();
296
297    // Convert and return the result of the function call.
298    m_objectMap->convertJSValueToNPVariant(exec, value, *result);
299    exec->clearException();
300
301    return true;
302}
303
304NPClass* NPJSObject::npClass()
305{
306    static NPClass npClass = {
307        NP_CLASS_STRUCT_VERSION,
308        NP_Allocate,
309        NP_Deallocate,
310        0,
311        NP_HasMethod,
312        NP_Invoke,
313        NP_InvokeDefault,
314        NP_HasProperty,
315        NP_GetProperty,
316        NP_SetProperty,
317        NP_RemoveProperty,
318        NP_Enumerate,
319        NP_Construct
320    };
321
322    return &npClass;
323}
324
325NPObject* NPJSObject::NP_Allocate(NPP npp, NPClass*)
326{
327    ASSERT_UNUSED(npp, !npp);
328
329    return new NPJSObject;
330}
331
332void NPJSObject::NP_Deallocate(NPObject* npObject)
333{
334    NPJSObject* npJSObject = toNPJSObject(npObject);
335    delete npJSObject;
336}
337
338bool NPJSObject::NP_HasMethod(NPObject* npObject, NPIdentifier methodName)
339{
340    return toNPJSObject(npObject)->hasMethod(methodName);
341}
342
343bool NPJSObject::NP_Invoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
344{
345    return toNPJSObject(npObject)->invoke(methodName, arguments, argumentCount, result);
346}
347
348bool NPJSObject::NP_InvokeDefault(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
349{
350    return toNPJSObject(npObject)->invokeDefault(arguments, argumentCount, result);
351}
352
353bool NPJSObject::NP_HasProperty(NPObject* npObject, NPIdentifier propertyName)
354{
355    return toNPJSObject(npObject)->hasProperty(propertyName);
356}
357
358bool NPJSObject::NP_GetProperty(NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
359{
360    return toNPJSObject(npObject)->getProperty(propertyName, result);
361}
362
363bool NPJSObject::NP_SetProperty(NPObject* npObject, NPIdentifier propertyName, const NPVariant* value)
364{
365    return toNPJSObject(npObject)->setProperty(propertyName, value);
366}
367
368bool NPJSObject::NP_RemoveProperty(NPObject* npObject, NPIdentifier propertyName)
369{
370    return toNPJSObject(npObject)->removeProperty(propertyName);
371}
372
373bool NPJSObject::NP_Enumerate(NPObject* npObject, NPIdentifier** identifiers, uint32_t* identifierCount)
374{
375    return toNPJSObject(npObject)->enumerate(identifiers, identifierCount);
376}
377
378bool NPJSObject::NP_Construct(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
379{
380    return toNPJSObject(npObject)->construct(arguments, argumentCount, result);
381}
382
383} // namespace WebKit
384