c_instance.cpp revision 5f1ab04193ad0130ca8204aadaceae083aca9881
1/*
2 * Copyright (C) 2003, 2006 Apple Computer, 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 COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#if ENABLE(NETSCAPE_PLUGIN_API)
29
30#include "c_instance.h"
31
32#include "c_class.h"
33#include "c_runtime.h"
34#include "c_utility.h"
35#include "IdentifierRep.h"
36#include "npruntime_impl.h"
37#include "runtime_root.h"
38#include <runtime/ArgList.h>
39#include <runtime/Error.h>
40#include <interpreter/CallFrame.h>
41#include <runtime/JSLock.h>
42#include <runtime/JSNumberCell.h>
43#include <runtime/PropertyNameArray.h>
44#include <wtf/Assertions.h>
45#include <wtf/StdLibExtras.h>
46#include <wtf/StringExtras.h>
47#include <wtf/Vector.h>
48
49using namespace WebCore;
50
51namespace JSC {
52namespace Bindings {
53
54using JSC::UString;
55
56static JSC::UString& globalExceptionString()
57{
58    DEFINE_STATIC_LOCAL(JSC::UString, exceptionStr, ());
59    return exceptionStr;
60}
61
62void CInstance::setGlobalException(UString exception)
63{
64    globalExceptionString() = exception;
65}
66
67void CInstance::moveGlobalExceptionToExecState(ExecState* exec)
68{
69    if (globalExceptionString().isNull())
70        return;
71
72    {
73        JSLock lock(false);
74        throwError(exec, GeneralError, globalExceptionString());
75    }
76
77    globalExceptionString() = UString();
78}
79
80CInstance::CInstance(NPObject* o, PassRefPtr<RootObject> rootObject)
81    : Instance(rootObject)
82{
83    _object = _NPN_RetainObject(o);
84    _class = 0;
85}
86
87CInstance::~CInstance()
88{
89    _NPN_ReleaseObject(_object);
90}
91
92Class *CInstance::getClass() const
93{
94    if (!_class)
95        _class = CClass::classForIsA(_object->_class);
96    return _class;
97}
98
99bool CInstance::supportsInvokeDefaultMethod() const
100{
101    return _object->_class->invokeDefault;
102}
103
104JSValue CInstance::invokeMethod(ExecState* exec, const MethodList& methodList, const ArgList& args)
105{
106    // Overloading methods are not allowed by NPObjects.  Should only be one
107    // name match for a particular method.
108    ASSERT(methodList.size() == 1);
109
110    CMethod* method = static_cast<CMethod*>(methodList[0]);
111
112    NPIdentifier ident = method->identifier();
113    if (!_object->_class->hasMethod(_object, ident))
114        return jsUndefined();
115
116    unsigned count = args.size();
117    Vector<NPVariant, 8> cArgs(count);
118
119    unsigned i;
120    for (i = 0; i < count; i++)
121        convertValueToNPVariant(exec, args.at(i), &cArgs[i]);
122
123    // Invoke the 'C' method.
124#ifdef ANDROID_NPN_SETEXCEPTION
125    SetGlobalException(0);
126#endif
127    NPVariant resultVariant;
128    VOID_TO_NPVARIANT(resultVariant);
129
130    {
131        JSLock::DropAllLocks dropAllLocks(false);
132        ASSERT(globalExceptionString().isNull());
133        _object->_class->invoke(_object, ident, cArgs.data(), count, &resultVariant);
134        moveGlobalExceptionToExecState(exec);
135    }
136
137    for (i = 0; i < count; i++)
138        _NPN_ReleaseVariantValue(&cArgs[i]);
139
140    JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, _rootObject.get());
141    _NPN_ReleaseVariantValue(&resultVariant);
142#ifdef ANDROID_NPN_SETEXCEPTION
143    MoveGlobalExceptionToExecState(exec);
144#endif
145    return resultValue;
146}
147
148
149JSValue CInstance::invokeDefaultMethod(ExecState* exec, const ArgList& args)
150{
151    if (!_object->_class->invokeDefault)
152        return jsUndefined();
153
154    unsigned count = args.size();
155    Vector<NPVariant, 8> cArgs(count);
156
157    unsigned i;
158    for (i = 0; i < count; i++)
159        convertValueToNPVariant(exec, args.at(i), &cArgs[i]);
160
161    // Invoke the 'C' method.
162#ifdef ANDROID_NPN_SETEXCEPTION
163    SetGlobalException(0);
164#endif
165    NPVariant resultVariant;
166    VOID_TO_NPVARIANT(resultVariant);
167    {
168        JSLock::DropAllLocks dropAllLocks(false);
169        ASSERT(globalExceptionString().isNull());
170        _object->_class->invokeDefault(_object, cArgs.data(), count, &resultVariant);
171        moveGlobalExceptionToExecState(exec);
172    }
173
174    for (i = 0; i < count; i++)
175        _NPN_ReleaseVariantValue(&cArgs[i]);
176
177    JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, _rootObject.get());
178    _NPN_ReleaseVariantValue(&resultVariant);
179#ifdef ANDROID_NPN_SETEXCEPTION
180    MoveGlobalExceptionToExecState(exec);
181#endif
182    return resultValue;
183}
184
185bool CInstance::supportsConstruct() const
186{
187    return _object->_class->construct;
188}
189
190JSValue CInstance::invokeConstruct(ExecState* exec, const ArgList& args)
191{
192    if (!_object->_class->construct)
193        return jsUndefined();
194
195    unsigned count = args.size();
196    Vector<NPVariant, 8> cArgs(count);
197
198    unsigned i;
199    for (i = 0; i < count; i++)
200        convertValueToNPVariant(exec, args.at(i), &cArgs[i]);
201
202    // Invoke the 'C' method.
203    NPVariant resultVariant;
204    VOID_TO_NPVARIANT(resultVariant);
205    {
206        JSLock::DropAllLocks dropAllLocks(false);
207        ASSERT(globalExceptionString().isNull());
208        _object->_class->construct(_object, cArgs.data(), count, &resultVariant);
209        moveGlobalExceptionToExecState(exec);
210    }
211
212    for (i = 0; i < count; i++)
213        _NPN_ReleaseVariantValue(&cArgs[i]);
214
215    JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, _rootObject.get());
216    _NPN_ReleaseVariantValue(&resultVariant);
217    return resultValue;
218}
219
220JSValue CInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
221{
222    if (hint == PreferString)
223        return stringValue(exec);
224    if (hint == PreferNumber)
225        return numberValue(exec);
226    return valueOf(exec);
227}
228
229JSValue CInstance::stringValue(ExecState* exec) const
230{
231    char buf[1024];
232    snprintf(buf, sizeof(buf), "NPObject %p, NPClass %p", _object, _object->_class);
233    return jsString(exec, buf);
234}
235
236JSValue CInstance::numberValue(ExecState* exec) const
237{
238    // FIXME: Implement something sensible.
239    return jsNumber(exec, 0);
240}
241
242JSValue CInstance::booleanValue() const
243{
244    // FIXME: Implement something sensible.
245    return jsBoolean(false);
246}
247
248JSValue CInstance::valueOf(ExecState* exec) const
249{
250    return stringValue(exec);
251}
252
253void CInstance::getPropertyNames(ExecState* exec, PropertyNameArray& nameArray)
254{
255    if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(_object->_class) || !_object->_class->enumerate)
256        return;
257
258    uint32_t count;
259    NPIdentifier* identifiers;
260
261    {
262        JSLock::DropAllLocks dropAllLocks(false);
263        ASSERT(globalExceptionString().isNull());
264        bool ok = _object->_class->enumerate(_object, &identifiers, &count);
265        moveGlobalExceptionToExecState(exec);
266        if (!ok)
267            return;
268    }
269
270    for (uint32_t i = 0; i < count; i++) {
271        IdentifierRep* identifier = static_cast<IdentifierRep*>(identifiers[i]);
272
273        if (identifier->isString())
274            nameArray.add(identifierFromNPIdentifier(identifier->string()));
275        else
276            nameArray.add(Identifier::from(exec, identifier->number()));
277    }
278
279    // FIXME: This should really call NPN_MemFree but that's in WebKit
280    free(identifiers);
281}
282
283}
284}
285
286#endif // ENABLE(NETSCAPE_PLUGIN_API)
287