Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / v8 / V8NPObject.cpp
1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009 Google 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 are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32
33 #include "bindings/v8/V8NPObject.h"
34
35 #include "V8HTMLAppletElement.h"
36 #include "V8HTMLEmbedElement.h"
37 #include "V8HTMLObjectElement.h"
38 #include "bindings/v8/NPV8Object.h"
39 #include "bindings/v8/V8Binding.h"
40 #include "bindings/v8/V8NPUtils.h"
41 #include "bindings/v8/V8ObjectConstructor.h"
42 #include "bindings/v8/V8PersistentValueMap.h"
43 #include "bindings/v8/npruntime_impl.h"
44 #include "bindings/v8/npruntime_priv.h"
45 #include "core/html/HTMLPlugInElement.h"
46 #include "v8-util.h"
47 #include "wtf/OwnPtr.h"
48
49 namespace WebCore {
50
51 enum InvokeFunctionType {
52     InvokeMethod = 1,
53     InvokeConstruct = 2,
54     InvokeDefault = 3
55 };
56
57 struct IdentifierRep {
58     int number() const { return m_isString ? 0 : m_value.m_number; }
59     const char* string() const { return m_isString ? m_value.m_string : 0; }
60
61     union {
62         const char* m_string;
63         int m_number;
64     } m_value;
65     bool m_isString;
66 };
67
68 // FIXME: need comments.
69 // Params: holder could be HTMLEmbedElement or NPObject
70 static void npObjectInvokeImpl(const v8::FunctionCallbackInfo<v8::Value>& info, InvokeFunctionType functionId)
71 {
72     NPObject* npObject;
73     v8::Isolate* isolate = info.GetIsolate();
74
75     // These three types are subtypes of HTMLPlugInElement.
76     HTMLPlugInElement* element = V8HTMLAppletElement::toNativeWithTypeCheck(isolate, info.Holder());
77     if (!element) {
78         element = V8HTMLEmbedElement::toNativeWithTypeCheck(isolate, info.Holder());
79         if (!element) {
80             element = V8HTMLObjectElement::toNativeWithTypeCheck(isolate, info.Holder());
81         }
82     }
83     if (element) {
84         if (RefPtr<SharedPersistent<v8::Object> > wrapper = element->pluginWrapper()) {
85             v8::HandleScope handleScope(isolate);
86             npObject = v8ObjectToNPObject(wrapper->newLocal(isolate));
87         } else
88             npObject = 0;
89     } else {
90         // The holder object is not a subtype of HTMLPlugInElement, it must be an NPObject which has three
91         // internal fields.
92         if (info.Holder()->InternalFieldCount() != npObjectInternalFieldCount) {
93             throwError(v8ReferenceError, "NPMethod called on non-NPObject", info.GetIsolate());
94             return;
95         }
96
97         npObject = v8ObjectToNPObject(info.Holder());
98     }
99
100     // Verify that our wrapper wasn't using a NPObject which has already been deleted.
101     if (!npObject || !_NPN_IsAlive(npObject)) {
102         throwError(v8ReferenceError, "NPObject deleted", isolate);
103         return;
104     }
105
106     // Wrap up parameters.
107     int numArgs = info.Length();
108     OwnPtr<NPVariant[]> npArgs = adoptArrayPtr(new NPVariant[numArgs]);
109
110     for (int i = 0; i < numArgs; i++)
111         convertV8ObjectToNPVariant(info[i], npObject, &npArgs[i], isolate);
112
113     NPVariant result;
114     VOID_TO_NPVARIANT(result);
115
116     bool retval = true;
117     switch (functionId) {
118     case InvokeMethod:
119         if (npObject->_class->invoke) {
120             v8::Handle<v8::String> functionName = v8::Handle<v8::String>::Cast(info.Data());
121             NPIdentifier identifier = getStringIdentifier(functionName);
122             retval = npObject->_class->invoke(npObject, identifier, npArgs.get(), numArgs, &result);
123         }
124         break;
125     case InvokeConstruct:
126         if (npObject->_class->construct)
127             retval = npObject->_class->construct(npObject, npArgs.get(), numArgs, &result);
128         break;
129     case InvokeDefault:
130         if (npObject->_class->invokeDefault)
131             retval = npObject->_class->invokeDefault(npObject, npArgs.get(), numArgs, &result);
132         break;
133     default:
134         break;
135     }
136
137     if (!retval)
138         throwError(v8GeneralError, "Error calling method on NPObject.", isolate);
139
140     for (int i = 0; i < numArgs; i++)
141         _NPN_ReleaseVariantValue(&npArgs[i]);
142
143     // Unwrap return values.
144     v8::Handle<v8::Value> returnValue;
145     if (_NPN_IsAlive(npObject))
146         returnValue = convertNPVariantToV8Object(&result, npObject, isolate);
147     _NPN_ReleaseVariantValue(&result);
148
149     v8SetReturnValue(info, returnValue);
150 }
151
152
153 void npObjectMethodHandler(const v8::FunctionCallbackInfo<v8::Value>& info)
154 {
155     return npObjectInvokeImpl(info, InvokeMethod);
156 }
157
158
159 void npObjectInvokeDefaultHandler(const v8::FunctionCallbackInfo<v8::Value>& info)
160 {
161     if (info.IsConstructCall()) {
162         npObjectInvokeImpl(info, InvokeConstruct);
163         return;
164     }
165
166     npObjectInvokeImpl(info, InvokeDefault);
167 }
168
169 class V8TemplateMapTraits : public V8PersistentValueMapTraits<PrivateIdentifier*, v8::FunctionTemplate, true> {
170 public:
171     typedef v8::PersistentValueMap<PrivateIdentifier*, v8::FunctionTemplate, V8TemplateMapTraits> MapType;
172     typedef PrivateIdentifier WeakCallbackDataType;
173
174     static WeakCallbackDataType* WeakCallbackParameter(MapType* map, PrivateIdentifier* key, const v8::Local<v8::FunctionTemplate>& value)
175     {
176         return key;
177     }
178
179     static void DisposeCallbackData(WeakCallbackDataType* callbackData) { }
180
181     static MapType* MapFromWeakCallbackData(
182         const v8::WeakCallbackData<v8::FunctionTemplate, WeakCallbackDataType>&);
183
184     static PrivateIdentifier* KeyFromWeakCallbackData(
185         const v8::WeakCallbackData<v8::FunctionTemplate, WeakCallbackDataType>& data)
186     {
187         return data.GetParameter();
188     }
189
190     // Dispose traits:
191     static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<v8::FunctionTemplate> value, PrivateIdentifier* key) { }
192 };
193
194
195 class V8NPTemplateMap {
196 public:
197     // NPIdentifier is PrivateIdentifier*.
198     typedef v8::PersistentValueMap<PrivateIdentifier*, v8::FunctionTemplate, V8TemplateMapTraits> MapType;
199
200     v8::Local<v8::FunctionTemplate> get(PrivateIdentifier* key)
201     {
202         return m_map.Get(key);
203     }
204
205     void set(PrivateIdentifier* key, v8::Handle<v8::FunctionTemplate> handle)
206     {
207         ASSERT(!m_map.Contains(key));
208         m_map.Set(key, handle);
209     }
210
211     static V8NPTemplateMap& sharedInstance(v8::Isolate* isolate)
212     {
213         DEFINE_STATIC_LOCAL(V8NPTemplateMap, map, (isolate));
214         ASSERT(isolate == map.m_map.GetIsolate());
215         return map;
216     }
217
218     friend class V8TemplateMapTraits;
219
220 private:
221     explicit V8NPTemplateMap(v8::Isolate* isolate)
222         : m_map(isolate)
223     {
224     }
225
226     MapType m_map;
227 };
228
229 V8TemplateMapTraits::MapType* V8TemplateMapTraits::MapFromWeakCallbackData(const v8::WeakCallbackData<v8::FunctionTemplate, WeakCallbackDataType>& data)
230 {
231     return &V8NPTemplateMap::sharedInstance(data.GetIsolate()).m_map;
232 }
233
234
235 static v8::Handle<v8::Value> npObjectGetProperty(v8::Local<v8::Object> self, NPIdentifier identifier, v8::Local<v8::Value> key, v8::Isolate* isolate)
236 {
237     NPObject* npObject = v8ObjectToNPObject(self);
238
239     // Verify that our wrapper wasn't using a NPObject which
240     // has already been deleted.
241     if (!npObject || !_NPN_IsAlive(npObject))
242         return throwError(v8ReferenceError, "NPObject deleted", isolate);
243
244
245     if (npObject->_class->hasProperty && npObject->_class->getProperty && npObject->_class->hasProperty(npObject, identifier)) {
246         if (!_NPN_IsAlive(npObject))
247             return throwError(v8ReferenceError, "NPObject deleted", isolate);
248
249         NPVariant result;
250         VOID_TO_NPVARIANT(result);
251         if (!npObject->_class->getProperty(npObject, identifier, &result))
252             return v8Undefined();
253
254         v8::Handle<v8::Value> returnValue;
255         if (_NPN_IsAlive(npObject))
256             returnValue = convertNPVariantToV8Object(&result, npObject, isolate);
257         _NPN_ReleaseVariantValue(&result);
258         return returnValue;
259
260     }
261
262     if (!_NPN_IsAlive(npObject))
263         return throwError(v8ReferenceError, "NPObject deleted", isolate);
264
265     if (key->IsString() && npObject->_class->hasMethod && npObject->_class->hasMethod(npObject, identifier)) {
266         if (!_NPN_IsAlive(npObject))
267             return throwError(v8ReferenceError, "NPObject deleted", isolate);
268
269         PrivateIdentifier* id = static_cast<PrivateIdentifier*>(identifier);
270         v8::Local<v8::FunctionTemplate> functionTemplate = V8NPTemplateMap::sharedInstance(isolate).get(id);
271         // Cache templates using identifier as the key.
272         if (functionTemplate.IsEmpty()) {
273             // Create a new template.
274             functionTemplate = v8::FunctionTemplate::New(isolate);
275             functionTemplate->SetCallHandler(npObjectMethodHandler, key);
276             V8NPTemplateMap::sharedInstance(isolate).set(id, functionTemplate);
277         }
278         v8::Local<v8::Function> v8Function = functionTemplate->GetFunction();
279         v8Function->SetName(v8::Handle<v8::String>::Cast(key));
280         return v8Function;
281     }
282
283     return v8Undefined();
284 }
285
286 void npObjectNamedPropertyGetter(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info)
287 {
288     NPIdentifier identifier = getStringIdentifier(name);
289     v8SetReturnValue(info, npObjectGetProperty(info.Holder(), identifier, name, info.GetIsolate()));
290 }
291
292 void npObjectIndexedPropertyGetter(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info)
293 {
294     NPIdentifier identifier = _NPN_GetIntIdentifier(index);
295     v8SetReturnValue(info, npObjectGetProperty(info.Holder(), identifier, v8::Number::New(info.GetIsolate(), index), info.GetIsolate()));
296 }
297
298 void npObjectGetNamedProperty(v8::Local<v8::Object> self, v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info)
299 {
300     NPIdentifier identifier = getStringIdentifier(name);
301     v8SetReturnValue(info, npObjectGetProperty(self, identifier, name, info.GetIsolate()));
302 }
303
304 void npObjectGetIndexedProperty(v8::Local<v8::Object> self, uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info)
305 {
306     NPIdentifier identifier = _NPN_GetIntIdentifier(index);
307     v8SetReturnValue(info, npObjectGetProperty(self, identifier, v8::Number::New(info.GetIsolate(), index), info.GetIsolate()));
308 }
309
310 void npObjectQueryProperty(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Integer>& info)
311 {
312     NPIdentifier identifier = getStringIdentifier(name);
313     if (npObjectGetProperty(info.Holder(), identifier, name, info.GetIsolate()).IsEmpty())
314         return;
315     v8SetReturnValueInt(info, 0);
316 }
317
318 static v8::Handle<v8::Value> npObjectSetProperty(v8::Local<v8::Object> self, NPIdentifier identifier, v8::Local<v8::Value> value, v8::Isolate* isolate)
319 {
320     NPObject* npObject = v8ObjectToNPObject(self);
321
322     // Verify that our wrapper wasn't using a NPObject which has already been deleted.
323     if (!npObject || !_NPN_IsAlive(npObject)) {
324         throwError(v8ReferenceError, "NPObject deleted", isolate);
325         return value;  // Intercepted, but an exception was thrown.
326     }
327
328     if (npObject->_class->hasProperty && npObject->_class->setProperty && npObject->_class->hasProperty(npObject, identifier)) {
329         if (!_NPN_IsAlive(npObject))
330             return throwError(v8ReferenceError, "NPObject deleted", isolate);
331
332         NPVariant npValue;
333         VOID_TO_NPVARIANT(npValue);
334         convertV8ObjectToNPVariant(value, npObject, &npValue, isolate);
335         bool success = npObject->_class->setProperty(npObject, identifier, &npValue);
336         _NPN_ReleaseVariantValue(&npValue);
337         if (success)
338             return value; // Intercept the call.
339     }
340     return v8Undefined();
341 }
342
343
344 void npObjectNamedPropertySetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)
345 {
346     NPIdentifier identifier = getStringIdentifier(name);
347     v8SetReturnValue(info, npObjectSetProperty(info.Holder(), identifier, value, info.GetIsolate()));
348 }
349
350
351 void npObjectIndexedPropertySetter(uint32_t index, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)
352 {
353     NPIdentifier identifier = _NPN_GetIntIdentifier(index);
354     v8SetReturnValue(info, npObjectSetProperty(info.Holder(), identifier, value, info.GetIsolate()));
355 }
356
357 void npObjectSetNamedProperty(v8::Local<v8::Object> self, v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)
358 {
359     NPIdentifier identifier = getStringIdentifier(name);
360     v8SetReturnValue(info, npObjectSetProperty(self, identifier, value, info.GetIsolate()));
361 }
362
363 void npObjectSetIndexedProperty(v8::Local<v8::Object> self, uint32_t index, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)
364 {
365     NPIdentifier identifier = _NPN_GetIntIdentifier(index);
366     v8SetReturnValue(info, npObjectSetProperty(self, identifier, value, info.GetIsolate()));
367 }
368
369 void npObjectPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info, bool namedProperty)
370 {
371     NPObject* npObject = v8ObjectToNPObject(info.Holder());
372
373     // Verify that our wrapper wasn't using a NPObject which
374     // has already been deleted.
375     if (!npObject || !_NPN_IsAlive(npObject))
376         throwError(v8ReferenceError, "NPObject deleted", info.GetIsolate());
377
378     if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npObject->_class) && npObject->_class->enumerate) {
379         uint32_t count;
380         NPIdentifier* identifiers;
381         if (npObject->_class->enumerate(npObject, &identifiers, &count)) {
382             uint32_t propertiesCount = 0;
383             for (uint32_t i = 0; i < count; ++i) {
384                 IdentifierRep* identifier = static_cast<IdentifierRep*>(identifiers[i]);
385                 if (namedProperty == identifier->m_isString)
386                     ++propertiesCount;
387             }
388             v8::Handle<v8::Array> properties = v8::Array::New(info.GetIsolate(), propertiesCount);
389             for (uint32_t i = 0, propertyIndex = 0; i < count; ++i) {
390                 IdentifierRep* identifier = static_cast<IdentifierRep*>(identifiers[i]);
391                 if (namedProperty == identifier->m_isString) {
392                     ASSERT(propertyIndex < propertiesCount);
393                     if (namedProperty)
394                         properties->Set(v8::Integer::New(info.GetIsolate(), propertyIndex++), v8AtomicString(info.GetIsolate(), identifier->string()));
395                     else
396                         properties->Set(v8::Integer::New(info.GetIsolate(), propertyIndex++), v8::Integer::New(info.GetIsolate(), identifier->number()));
397                 }
398             }
399
400             v8SetReturnValue(info, properties);
401             return;
402         }
403     }
404 }
405
406 void npObjectNamedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info)
407 {
408     npObjectPropertyEnumerator(info, true);
409 }
410
411 void npObjectIndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info)
412 {
413     npObjectPropertyEnumerator(info, false);
414 }
415
416 static DOMWrapperMap<NPObject>& staticNPObjectMap()
417 {
418     DEFINE_STATIC_LOCAL(DOMWrapperMap<NPObject>, npObjectMap, (v8::Isolate::GetCurrent()));
419     return npObjectMap;
420 }
421
422 template <>
423 inline void DOMWrapperMap<NPObject>::PersistentValueMapTraits::Dispose(
424     v8::Isolate* isolate,
425     v8::UniquePersistent<v8::Object> value,
426     NPObject* npObject)
427 {
428     ASSERT(npObject);
429     if (_NPN_IsAlive(npObject))
430         _NPN_ReleaseObject(npObject);
431 }
432
433 v8::Local<v8::Object> createV8ObjectForNPObject(NPObject* object, NPObject* root, v8::Isolate* isolate)
434 {
435     static v8::Eternal<v8::FunctionTemplate> npObjectDesc;
436
437     ASSERT(isolate->InContext());
438
439     // If this is a v8 object, just return it.
440     V8NPObject* v8NPObject = npObjectToV8NPObject(object);
441     if (v8NPObject)
442         return v8::Local<v8::Object>::New(isolate, v8NPObject->v8Object);
443
444     // If we've already wrapped this object, just return it.
445     v8::Handle<v8::Object> wrapper = staticNPObjectMap().newLocal(object, isolate);
446     if (!wrapper.IsEmpty())
447         return wrapper;
448
449     // FIXME: we should create a Wrapper type as a subclass of JSObject. It has two internal fields, field 0 is the wrapped
450     // pointer, and field 1 is the type. There should be an api function that returns unused type id. The same Wrapper type
451     // can be used by DOM bindings.
452     if (npObjectDesc.IsEmpty()) {
453         v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
454         templ->InstanceTemplate()->SetInternalFieldCount(npObjectInternalFieldCount);
455         templ->InstanceTemplate()->SetNamedPropertyHandler(npObjectNamedPropertyGetter, npObjectNamedPropertySetter, npObjectQueryProperty, 0, npObjectNamedPropertyEnumerator);
456         templ->InstanceTemplate()->SetIndexedPropertyHandler(npObjectIndexedPropertyGetter, npObjectIndexedPropertySetter, 0, 0, npObjectIndexedPropertyEnumerator);
457         templ->InstanceTemplate()->SetCallAsFunctionHandler(npObjectInvokeDefaultHandler);
458         npObjectDesc.Set(isolate, templ);
459     }
460
461     // FIXME: Move staticNPObjectMap() to DOMDataStore.
462     // Use V8DOMWrapper::createWrapper() and
463     // V8DOMWrapper::associateObjectWithWrapper()
464     // to create a wrapper object.
465     v8::Handle<v8::Function> v8Function = npObjectDesc.Get(isolate)->GetFunction();
466     v8::Local<v8::Object> value = V8ObjectConstructor::newInstance(isolate, v8Function);
467     if (value.IsEmpty())
468         return value;
469
470     V8DOMWrapper::setNativeInfo(value, npObjectTypeInfo(), object);
471
472     // KJS retains the object as part of its wrapper (see Bindings::CInstance).
473     _NPN_RetainObject(object);
474     _NPN_RegisterObject(object, root);
475
476     WrapperConfiguration configuration = buildWrapperConfiguration(object, WrapperConfiguration::Dependent);
477     staticNPObjectMap().set(object, value, configuration);
478     ASSERT(V8DOMWrapper::isDOMWrapper(value));
479     return value;
480 }
481
482 void forgetV8ObjectForNPObject(NPObject* object)
483 {
484     v8::Isolate* isolate = v8::Isolate::GetCurrent();
485     v8::HandleScope scope(isolate);
486     v8::Handle<v8::Object> wrapper = staticNPObjectMap().newLocal(object, isolate);
487     if (!wrapper.IsEmpty()) {
488         V8DOMWrapper::clearNativeInfo(wrapper, npObjectTypeInfo());
489         staticNPObjectMap().removeAndDispose(object);
490         _NPN_ReleaseObject(object);
491     }
492 }
493
494 } // namespace WebCore