a32b44ea59690436c945173735d3e959094d60cd
[WebKit-https.git] / Source / WebCore / bindings / v8 / NPV8Object.cpp
1 /*
2  * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) 2007, 2008, 2009 Google, Inc.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28
29 #include "NPV8Object.h"
30
31 #include "PlatformSupport.h"
32 #include "DOMWindow.h"
33 #include "Frame.h"
34 #include "NPObjectWrapper.h"
35 #include <wtf/OwnArrayPtr.h>
36 #include "PlatformString.h"
37 #include "ScriptSourceCode.h"
38 #include "UserGestureIndicator.h"
39 #include "V8Binding.h"
40 #include "V8GCController.h"
41 #include "V8NPUtils.h"
42 #include "WrapperTypeInfo.h"
43 #include "npruntime_impl.h"
44 #include "npruntime_priv.h"
45
46 #include <stdio.h>
47 #include <wtf/StringExtras.h>
48
49 using namespace WebCore;
50
51 namespace WebCore {
52
53 WrapperTypeInfo* npObjectTypeInfo()
54 {
55     static WrapperTypeInfo typeInfo = { 0, 0, 0, 0, 0, WrapperTypeObjectPrototype };
56     return &typeInfo;
57 }
58
59 typedef Vector<V8NPObject*> V8NPObjectVector;
60 typedef HashMap<int, V8NPObjectVector> V8NPObjectMap;
61
62 static v8::Local<v8::Context> toV8Context(NPP npp, NPObject* npObject)
63 {
64     V8NPObject* object = reinterpret_cast<V8NPObject*>(npObject);
65     DOMWindow* window = object->rootObject;
66     if (!window || !window->isCurrentlyDisplayedInFrame())
67         return v8::Local<v8::Context>();
68     return ScriptController::mainWorldContext(object->rootObject->frame());
69 }
70
71 static V8NPObjectMap* staticV8NPObjectMap()
72 {
73     DEFINE_STATIC_LOCAL(V8NPObjectMap, v8npObjectMap, ());
74     return &v8npObjectMap;
75 }
76
77 // FIXME: Comments on why use malloc and free.
78 static NPObject* allocV8NPObject(NPP, NPClass*)
79 {
80     return static_cast<NPObject*>(malloc(sizeof(V8NPObject)));
81 }
82
83 static void freeV8NPObject(NPObject* npObject)
84 {
85     V8NPObject* v8NpObject = reinterpret_cast<V8NPObject*>(npObject);
86     if (int v8ObjectHash = v8NpObject->v8Object->GetIdentityHash()) {
87         V8NPObjectMap::iterator iter = staticV8NPObjectMap()->find(v8ObjectHash);
88         if (iter != staticV8NPObjectMap()->end()) {
89             V8NPObjectVector& objects = iter->second;
90             for (size_t index = 0; index < objects.size(); ++index) {
91                 if (objects.at(index) == v8NpObject) {
92                     objects.remove(index);
93                     break;
94                 }
95             }
96             if (objects.isEmpty())
97                 staticV8NPObjectMap()->remove(v8ObjectHash);
98         } else
99             ASSERT_NOT_REACHED();
100     } else {
101         ASSERT(!v8::Context::InContext());
102         staticV8NPObjectMap()->clear();
103     }
104
105 #ifndef NDEBUG
106     V8GCController::unregisterGlobalHandle(v8NpObject, v8NpObject->v8Object);
107 #endif
108     v8NpObject->v8Object.Dispose();
109     free(v8NpObject);
110 }
111
112 static PassOwnArrayPtr<v8::Handle<v8::Value> > createValueListFromVariantArgs(const NPVariant* arguments, uint32_t argumentCount, NPObject* owner)
113 {
114     OwnArrayPtr<v8::Handle<v8::Value> > argv = adoptArrayPtr(new v8::Handle<v8::Value>[argumentCount]);
115     for (uint32_t index = 0; index < argumentCount; index++) {
116         const NPVariant* arg = &arguments[index];
117         argv[index] = convertNPVariantToV8Object(arg, owner);
118     }
119     return argv.release();
120 }
121
122 // Create an identifier (null terminated utf8 char*) from the NPIdentifier.
123 static v8::Local<v8::String> npIdentifierToV8Identifier(NPIdentifier name)
124 {
125     PrivateIdentifier* identifier = static_cast<PrivateIdentifier*>(name);
126     if (identifier->isString)
127         return v8::String::New(static_cast<const char*>(identifier->value.string));
128
129     char buffer[32];
130     snprintf(buffer, sizeof(buffer), "%d", identifier->value.number);
131     return v8::String::New(buffer);
132 }
133
134 NPObject* v8ObjectToNPObject(v8::Handle<v8::Object> object)
135 {
136     return reinterpret_cast<NPObject*>(object->GetPointerFromInternalField(v8DOMWrapperObjectIndex)); 
137 }
138
139 static NPClass V8NPObjectClass = { NP_CLASS_STRUCT_VERSION,
140                                    allocV8NPObject,
141                                    freeV8NPObject,
142                                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
143
144 // NPAPI's npruntime functions.
145 NPClass* npScriptObjectClass = &V8NPObjectClass;
146
147 NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object> object, DOMWindow* root)
148 {
149     // Check to see if this object is already wrapped.
150     if (object->InternalFieldCount() == npObjectInternalFieldCount) {
151         WrapperTypeInfo* typeInfo = static_cast<WrapperTypeInfo*>(object->GetPointerFromInternalField(v8DOMWrapperTypeIndex));
152         if (typeInfo == npObjectTypeInfo()) {
153
154             NPObject* returnValue = v8ObjectToNPObject(object);
155             _NPN_RetainObject(returnValue);
156             return returnValue;
157         }
158     }
159
160     int v8ObjectHash = object->GetIdentityHash();
161     ASSERT(v8ObjectHash);
162     V8NPObjectMap::iterator iter = staticV8NPObjectMap()->find(v8ObjectHash);
163     if (iter != staticV8NPObjectMap()->end()) {
164         V8NPObjectVector& objects = iter->second;
165         for (size_t index = 0; index < objects.size(); ++index) {
166             V8NPObject* v8npObject = objects.at(index);
167             if (v8npObject->rootObject == root) {
168                 ASSERT(v8npObject->v8Object == object);
169                 _NPN_RetainObject(&v8npObject->object);
170                 return reinterpret_cast<NPObject*>(v8npObject);
171             }
172         }
173     } else {
174         iter = staticV8NPObjectMap()->set(v8ObjectHash, V8NPObjectVector()).iterator;
175     }
176
177     V8NPObject* v8npObject = reinterpret_cast<V8NPObject*>(_NPN_CreateObject(npp, &V8NPObjectClass));
178     v8npObject->v8Object = v8::Persistent<v8::Object>::New(object);
179 #ifndef NDEBUG
180     V8GCController::registerGlobalHandle(NPOBJECT, v8npObject, v8npObject->v8Object);
181 #endif
182     v8npObject->rootObject = root;
183
184     iter->second.append(v8npObject);
185
186     return reinterpret_cast<NPObject*>(v8npObject);
187 }
188
189 } // namespace WebCore
190
191 bool _NPN_Invoke(NPP npp, NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
192 {
193     if (!npObject)
194         return false;
195
196     if (npObject->_class != npScriptObjectClass) {
197         if (npObject->_class->invoke)
198             return npObject->_class->invoke(npObject, methodName, arguments, argumentCount, result);
199
200         VOID_TO_NPVARIANT(*result);
201         return true;
202     }
203
204     V8NPObject* v8NpObject = reinterpret_cast<V8NPObject*>(npObject);
205
206     PrivateIdentifier* identifier = static_cast<PrivateIdentifier*>(methodName);
207     if (!identifier->isString)
208         return false;
209
210     if (!strcmp(identifier->value.string, "eval")) {
211         if (argumentCount != 1)
212             return false;
213         if (arguments[0].type != NPVariantType_String)
214             return false;
215         return _NPN_Evaluate(npp, npObject, const_cast<NPString*>(&arguments[0].value.stringValue), result);
216     }
217
218     v8::HandleScope handleScope;
219     // FIXME: should use the plugin's owner frame as the security context.
220     v8::Handle<v8::Context> context = toV8Context(npp, npObject);
221     if (context.IsEmpty())
222         return false;
223
224     v8::Context::Scope scope(context);
225     ExceptionCatcher exceptionCatcher;
226
227     v8::Handle<v8::Value> functionObject = v8NpObject->v8Object->Get(v8::String::New(identifier->value.string));
228     if (functionObject.IsEmpty() || functionObject->IsNull()) {
229         NULL_TO_NPVARIANT(*result);
230         return false;
231     }
232     if (functionObject->IsUndefined()) {
233         VOID_TO_NPVARIANT(*result);
234         return false;
235     }
236
237     Frame* frame = v8NpObject->rootObject->frame();
238     ASSERT(frame);
239
240     // Call the function object.
241     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(functionObject);
242     OwnArrayPtr<v8::Handle<v8::Value> > argv = createValueListFromVariantArgs(arguments, argumentCount, npObject);
243     v8::Local<v8::Value> resultObject = frame->script()->callFunction(function, v8NpObject->v8Object, argumentCount, argv.get());
244
245     // If we had an error, return false.  The spec is a little unclear here, but says "Returns true if the method was
246     // successfully invoked".  If we get an error return value, was that successfully invoked?
247     if (resultObject.IsEmpty())
248         return false;
249
250     convertV8ObjectToNPVariant(resultObject, npObject, result);
251     return true;
252 }
253
254 // FIXME: Fix it same as _NPN_Invoke (HandleScope and such).
255 bool _NPN_InvokeDefault(NPP npp, NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
256 {
257     if (!npObject)
258         return false;
259
260     if (npObject->_class != npScriptObjectClass) {
261         if (npObject->_class->invokeDefault)
262             return npObject->_class->invokeDefault(npObject, arguments, argumentCount, result);
263
264         VOID_TO_NPVARIANT(*result);
265         return true;
266     }
267
268     V8NPObject* v8NpObject = reinterpret_cast<V8NPObject*>(npObject);
269
270     VOID_TO_NPVARIANT(*result);
271
272     v8::HandleScope handleScope;
273     v8::Handle<v8::Context> context = toV8Context(npp, npObject);
274     if (context.IsEmpty())
275         return false;
276
277     v8::Context::Scope scope(context);
278     ExceptionCatcher exceptionCatcher;
279
280     // Lookup the function object and call it.
281     v8::Handle<v8::Object> functionObject(v8NpObject->v8Object);
282     if (!functionObject->IsFunction())
283         return false;
284
285     v8::Local<v8::Value> resultObject;
286     v8::Handle<v8::Function> function(v8::Function::Cast(*functionObject));
287     if (!function->IsNull()) {
288         Frame* frame = v8NpObject->rootObject->frame();
289         ASSERT(frame);
290
291         OwnArrayPtr<v8::Handle<v8::Value> > argv = createValueListFromVariantArgs(arguments, argumentCount, npObject);
292         resultObject = frame->script()->callFunction(function, functionObject, argumentCount, argv.get());
293     }
294     // If we had an error, return false.  The spec is a little unclear here, but says "Returns true if the method was
295     // successfully invoked".  If we get an error return value, was that successfully invoked?
296     if (resultObject.IsEmpty())
297         return false;
298
299     convertV8ObjectToNPVariant(resultObject, npObject, result);
300     return true;
301 }
302
303 bool _NPN_Evaluate(NPP npp, NPObject* npObject, NPString* npScript, NPVariant* result)
304 {
305     bool popupsAllowed = PlatformSupport::popupsAllowed(npp);
306     return _NPN_EvaluateHelper(npp, popupsAllowed, npObject, npScript, result);
307 }
308
309 bool _NPN_EvaluateHelper(NPP npp, bool popupsAllowed, NPObject* npObject, NPString* npScript, NPVariant* result)
310 {
311     VOID_TO_NPVARIANT(*result);
312     if (!npObject)
313         return false;
314
315     if (npObject->_class != npScriptObjectClass) {
316         // Check if the object passed in is wrapped. If yes, then we need to invoke on the underlying object.
317         NPObject* actualObject = NPObjectWrapper::getUnderlyingNPObject(npObject);
318         if (!actualObject)
319             return false;
320         npObject = actualObject;
321     }
322
323     v8::HandleScope handleScope;
324     v8::Handle<v8::Context> context = toV8Context(npp, npObject);
325     if (context.IsEmpty())
326         return false;
327
328     v8::Context::Scope scope(context);
329     ExceptionCatcher exceptionCatcher;
330
331     // FIXME: Is this branch still needed after switching to using UserGestureIndicator?
332     String filename;
333     if (!popupsAllowed)
334         filename = "npscript";
335
336     V8NPObject* v8NpObject = reinterpret_cast<V8NPObject*>(npObject);
337     Frame* frame = v8NpObject->rootObject->frame();
338     ASSERT(frame);
339
340     String script = String::fromUTF8(npScript->UTF8Characters, npScript->UTF8Length);
341
342     UserGestureIndicator gestureIndicator(popupsAllowed ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
343     v8::Local<v8::Value> v8result = frame->script()->compileAndRunScript(ScriptSourceCode(script, KURL(ParsedURLString, filename)));
344
345     if (v8result.IsEmpty())
346         return false;
347
348     if (_NPN_IsAlive(npObject))
349         convertV8ObjectToNPVariant(v8result, npObject, result);
350     return true;
351 }
352
353 bool _NPN_GetProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
354 {
355     if (!npObject)
356         return false;
357
358     if (npObject->_class == npScriptObjectClass) {
359         V8NPObject* object = reinterpret_cast<V8NPObject*>(npObject);
360
361         v8::HandleScope handleScope;
362         v8::Handle<v8::Context> context = toV8Context(npp, npObject);
363         if (context.IsEmpty())
364             return false;
365
366         v8::Context::Scope scope(context);
367         ExceptionCatcher exceptionCatcher;
368
369         v8::Handle<v8::Object> obj(object->v8Object);
370         v8::Local<v8::Value> v8result = obj->Get(npIdentifierToV8Identifier(propertyName));
371         
372         if (v8result.IsEmpty())
373             return false;
374
375         convertV8ObjectToNPVariant(v8result, npObject, result);
376         return true;
377     }
378
379     if (npObject->_class->hasProperty && npObject->_class->getProperty) {
380         if (npObject->_class->hasProperty(npObject, propertyName))
381             return npObject->_class->getProperty(npObject, propertyName, result);
382     }
383
384     VOID_TO_NPVARIANT(*result);
385     return false;
386 }
387
388 bool _NPN_SetProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName, const NPVariant* value)
389 {
390     if (!npObject)
391         return false;
392
393     if (npObject->_class == npScriptObjectClass) {
394         V8NPObject* object = reinterpret_cast<V8NPObject*>(npObject);
395
396         v8::HandleScope handleScope;
397         v8::Handle<v8::Context> context = toV8Context(npp, npObject);
398         if (context.IsEmpty())
399             return false;
400
401         v8::Context::Scope scope(context);
402         ExceptionCatcher exceptionCatcher;
403
404         v8::Handle<v8::Object> obj(object->v8Object);
405         obj->Set(npIdentifierToV8Identifier(propertyName),
406                  convertNPVariantToV8Object(value, object->rootObject->frame()->script()->windowScriptNPObject()));
407         return true;
408     }
409
410     if (npObject->_class->setProperty)
411         return npObject->_class->setProperty(npObject, propertyName, value);
412
413     return false;
414 }
415
416 bool _NPN_RemoveProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName)
417 {
418     if (!npObject)
419         return false;
420     if (npObject->_class != npScriptObjectClass)
421         return false;
422
423     V8NPObject* object = reinterpret_cast<V8NPObject*>(npObject);
424
425     v8::HandleScope handleScope;
426     v8::Handle<v8::Context> context = toV8Context(npp, npObject);
427     if (context.IsEmpty())
428         return false;
429     v8::Context::Scope scope(context);
430     ExceptionCatcher exceptionCatcher;
431
432     v8::Handle<v8::Object> obj(object->v8Object);
433     // FIXME: Verify that setting to undefined is right.
434     obj->Set(npIdentifierToV8Identifier(propertyName), v8::Undefined());
435     return true;
436 }
437
438 bool _NPN_HasProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName)
439 {
440     if (!npObject)
441         return false;
442
443     if (npObject->_class == npScriptObjectClass) {
444         V8NPObject* object = reinterpret_cast<V8NPObject*>(npObject);
445
446         v8::HandleScope handleScope;
447         v8::Handle<v8::Context> context = toV8Context(npp, npObject);
448         if (context.IsEmpty())
449             return false;
450         v8::Context::Scope scope(context);
451         ExceptionCatcher exceptionCatcher;
452
453         v8::Handle<v8::Object> obj(object->v8Object);
454         return obj->Has(npIdentifierToV8Identifier(propertyName));
455     }
456
457     if (npObject->_class->hasProperty)
458         return npObject->_class->hasProperty(npObject, propertyName);
459     return false;
460 }
461
462 bool _NPN_HasMethod(NPP npp, NPObject* npObject, NPIdentifier methodName)
463 {
464     if (!npObject)
465         return false;
466
467     if (npObject->_class == npScriptObjectClass) {
468         V8NPObject* object = reinterpret_cast<V8NPObject*>(npObject);
469
470         v8::HandleScope handleScope;
471         v8::Handle<v8::Context> context = toV8Context(npp, npObject);
472         if (context.IsEmpty())
473             return false;
474         v8::Context::Scope scope(context);
475         ExceptionCatcher exceptionCatcher;
476
477         v8::Handle<v8::Object> obj(object->v8Object);
478         v8::Handle<v8::Value> prop = obj->Get(npIdentifierToV8Identifier(methodName));
479         return prop->IsFunction();
480     }
481
482     if (npObject->_class->hasMethod)
483         return npObject->_class->hasMethod(npObject, methodName);
484     return false;
485 }
486
487 void _NPN_SetException(NPObject* npObject, const NPUTF8 *message)
488 {
489     if (!npObject || npObject->_class != npScriptObjectClass) {
490         // We won't be able to find a proper scope for this exception, so just throw it.
491         // This is consistent with JSC, which throws a global exception all the time.
492         throwError(GeneralError, message);
493         return;
494     }
495     v8::HandleScope handleScope;
496     v8::Handle<v8::Context> context = toV8Context(0, npObject);
497     if (context.IsEmpty())
498         return;
499
500     v8::Context::Scope scope(context);
501     ExceptionCatcher exceptionCatcher;
502
503     throwError(GeneralError, message);
504 }
505
506 bool _NPN_Enumerate(NPP npp, NPObject* npObject, NPIdentifier** identifier, uint32_t* count)
507 {
508     if (!npObject)
509         return false;
510
511     if (npObject->_class == npScriptObjectClass) {
512         V8NPObject* object = reinterpret_cast<V8NPObject*>(npObject);
513
514         v8::HandleScope handleScope;
515         v8::Handle<v8::Context> context = toV8Context(npp, npObject);
516         if (context.IsEmpty())
517             return false;
518         v8::Context::Scope scope(context);
519         ExceptionCatcher exceptionCatcher;
520
521         v8::Handle<v8::Object> obj(object->v8Object);
522
523         // FIXME: http://b/issue?id=1210340: Use a v8::Object::Keys() method when it exists, instead of evaluating javascript.
524
525         // FIXME: Figure out how to cache this helper function.  Run a helper function that collects the properties
526         // on the object into an array.
527         const char enumeratorCode[] =
528             "(function (obj) {"
529             "  var props = [];"
530             "  for (var prop in obj) {"
531             "    props[props.length] = prop;"
532             "  }"
533             "  return props;"
534             "});";
535         v8::Handle<v8::String> source = v8::String::New(enumeratorCode);
536         v8::Handle<v8::Script> script = v8::Script::Compile(source, 0);
537         v8::Handle<v8::Value> enumeratorObj = script->Run();
538         v8::Handle<v8::Function> enumerator = v8::Handle<v8::Function>::Cast(enumeratorObj);
539         v8::Handle<v8::Value> argv[] = { obj };
540         v8::Local<v8::Value> propsObj = enumerator->Call(v8::Handle<v8::Object>::Cast(enumeratorObj), ARRAYSIZE_UNSAFE(argv), argv);
541         if (propsObj.IsEmpty())
542             return false;
543
544         // Convert the results into an array of NPIdentifiers.
545         v8::Handle<v8::Array> props = v8::Handle<v8::Array>::Cast(propsObj);
546         *count = props->Length();
547         *identifier = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier*) * *count));
548         for (uint32_t i = 0; i < *count; ++i) {
549             v8::Local<v8::Value> name = props->Get(v8Integer(i));
550             (*identifier)[i] = getStringIdentifier(v8::Local<v8::String>::Cast(name));
551         }
552         return true;
553     }
554
555     if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npObject->_class) && npObject->_class->enumerate)
556        return npObject->_class->enumerate(npObject, identifier, count);
557
558     return false;
559 }
560
561 bool _NPN_Construct(NPP npp, NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
562 {
563     if (!npObject)
564         return false;
565
566     if (npObject->_class == npScriptObjectClass) {
567         V8NPObject* object = reinterpret_cast<V8NPObject*>(npObject);
568
569         v8::HandleScope handleScope;
570         v8::Handle<v8::Context> context = toV8Context(npp, npObject);
571         if (context.IsEmpty())
572             return false;
573         v8::Context::Scope scope(context);
574         ExceptionCatcher exceptionCatcher;
575
576         // Lookup the constructor function.
577         v8::Handle<v8::Object> ctorObj(object->v8Object);
578         if (!ctorObj->IsFunction())
579             return false;
580
581         // Call the constructor.
582         v8::Local<v8::Value> resultObject;
583         v8::Handle<v8::Function> ctor(v8::Function::Cast(*ctorObj));
584         if (!ctor->IsNull()) {
585             Frame* frame = object->rootObject->frame();
586             ASSERT(frame);
587             OwnArrayPtr<v8::Handle<v8::Value> > argv = createValueListFromVariantArgs(arguments, argumentCount, npObject);
588             resultObject = V8ObjectConstructor::newInstanceInDocument(ctor, argumentCount, argv.get(), frame ? frame->document() : 0);
589         }
590
591         if (resultObject.IsEmpty())
592             return false;
593
594         convertV8ObjectToNPVariant(resultObject, npObject, result);
595         return true;
596     }
597
598     if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(npObject->_class) && npObject->_class->construct)
599         return npObject->_class->construct(npObject, arguments, argumentCount, result);
600
601     return false;
602 }