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