initial import
[vuplus_webkit] / Source / JavaScriptCore / qt / api / qscriptoriginalglobalobject_p.h
1 /*
2     Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Library General Public
6     License as published by the Free Software Foundation; either
7     version 2 of the License, or (at your option) any later version.
8
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Library General Public License for more details.
13
14     You should have received a copy of the GNU Library General Public License
15     along with this library; see the file COPYING.LIB.  If not, write to
16     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     Boston, MA 02110-1301, USA.
18 */
19
20 #ifndef qscriptoriginalglobalobject_p_h
21 #define qscriptoriginalglobalobject_p_h
22
23 #include <JavaScriptCore/JavaScript.h>
24 #include <JavaScriptCore/JSRetainPtr.h>
25 #include <QtCore/qvector.h>
26
27 /*!
28     \internal
29     This class is a workaround for missing JSC C API functionality. This class keeps all important
30     properties of an original (default) global object, so we can use it even if the global object was
31     changed.
32
33     FIXME this class is a container for workarounds :-) it should be replaced by proper JSC C API calls.
34
35     The class have to be created on the QScriptEnginePrivate creation time (before any change got applied to
36     global object).
37 */
38 class QScriptOriginalGlobalObject {
39 public:
40     inline QScriptOriginalGlobalObject(JSGlobalContextRef context);
41     inline ~QScriptOriginalGlobalObject();
42
43     inline bool objectHasOwnProperty(JSObjectRef object, JSStringRef property) const;
44     inline QVector<JSStringRef> objectGetOwnPropertyNames(JSObjectRef object) const;
45
46     inline bool isDate(JSValueRef value) const;
47     inline bool isArray(JSValueRef value) const;
48     inline bool isError(JSValueRef value) const;
49
50     inline JSValueRef functionPrototype() const;
51 private:
52     inline bool isType(JSValueRef value, JSObjectRef constructor, JSValueRef prototype) const;
53     inline void initializeMember(JSObjectRef globalObject, JSStringRef prototypeName, const char* type, JSObjectRef& constructor, JSValueRef& prototype);
54
55     // Copy of the global context reference (the same as in QScriptEnginePrivate).
56     JSGlobalContextRef m_context;
57
58     // Copy of constructors and prototypes used in isType functions.
59     JSObjectRef m_arrayConstructor;
60     JSValueRef m_arrayPrototype;
61     JSObjectRef m_errorConstructor;
62     JSValueRef m_errorPrototype;
63     JSObjectRef m_functionConstructor;
64     JSValueRef m_functionPrototype;
65     JSObjectRef m_dateConstructor;
66     JSValueRef m_datePrototype;
67
68     // Reference to standard JS functions that are not exposed by JSC C API.
69     JSObjectRef m_hasOwnPropertyFunction;
70     JSObjectRef m_getOwnPropertyNamesFunction;
71 };
72
73 QScriptOriginalGlobalObject::QScriptOriginalGlobalObject(JSGlobalContextRef context)
74     : m_context(JSGlobalContextRetain(context))
75 {
76     JSObjectRef globalObject = JSContextGetGlobalObject(m_context);
77     JSValueRef exception = 0;
78     JSRetainPtr<JSStringRef> propertyName;
79
80     propertyName.adopt(JSStringCreateWithUTF8CString("prototype"));
81     initializeMember(globalObject, propertyName.get(), "Array", m_arrayConstructor, m_arrayPrototype);
82     initializeMember(globalObject, propertyName.get(), "Error", m_errorConstructor, m_errorPrototype);
83     initializeMember(globalObject, propertyName.get(), "Function", m_functionConstructor, m_functionPrototype);
84     initializeMember(globalObject, propertyName.get(), "Date", m_dateConstructor, m_datePrototype);
85
86     propertyName.adopt(JSStringCreateWithUTF8CString("hasOwnProperty"));
87     m_hasOwnPropertyFunction = const_cast<JSObjectRef>(JSObjectGetProperty(m_context, globalObject, propertyName.get(), &exception));
88     JSValueProtect(m_context, m_hasOwnPropertyFunction);
89     Q_ASSERT(JSValueIsObject(m_context, m_hasOwnPropertyFunction));
90     Q_ASSERT(JSObjectIsFunction(m_context, m_hasOwnPropertyFunction));
91     Q_ASSERT(!exception);
92
93     propertyName.adopt(JSStringCreateWithUTF8CString("Object"));
94     JSObjectRef objectConstructor
95             = const_cast<JSObjectRef>(JSObjectGetProperty(m_context, globalObject, propertyName.get(), &exception));
96     propertyName.adopt(JSStringCreateWithUTF8CString("getOwnPropertyNames"));
97     m_getOwnPropertyNamesFunction
98             = const_cast<JSObjectRef>(JSObjectGetProperty(m_context, objectConstructor, propertyName.get(), &exception));
99     JSValueProtect(m_context, m_getOwnPropertyNamesFunction);
100     Q_ASSERT(JSValueIsObject(m_context, m_getOwnPropertyNamesFunction));
101     Q_ASSERT(JSObjectIsFunction(m_context, m_getOwnPropertyNamesFunction));
102     Q_ASSERT(!exception);
103 }
104
105 inline void QScriptOriginalGlobalObject::initializeMember(JSObjectRef globalObject, JSStringRef prototypeName, const char* type, JSObjectRef& constructor, JSValueRef& prototype)
106 {
107     JSRetainPtr<JSStringRef> typeName(Adopt, JSStringCreateWithUTF8CString(type));
108     JSValueRef exception = 0;
109
110     // Save references to the Type constructor and prototype.
111     JSValueRef typeConstructor = JSObjectGetProperty(m_context, globalObject, typeName.get(), &exception);
112     Q_ASSERT(JSValueIsObject(m_context, typeConstructor));
113     constructor = JSValueToObject(m_context, typeConstructor, &exception);
114     JSValueProtect(m_context, constructor);
115
116     // Note that this is not the [[Prototype]] internal property (which we could
117     // get via JSObjectGetPrototype), but the Type.prototype, that will be set
118     // as [[Prototype]] of Type instances.
119     prototype = JSObjectGetProperty(m_context, constructor, prototypeName, &exception);
120     Q_ASSERT(JSValueIsObject(m_context, prototype));
121     JSValueProtect(m_context, prototype);
122     Q_ASSERT(!exception);
123 }
124
125 QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject()
126 {
127     JSValueUnprotect(m_context, m_arrayConstructor);
128     JSValueUnprotect(m_context, m_arrayPrototype);
129     JSValueUnprotect(m_context, m_errorConstructor);
130     JSValueUnprotect(m_context, m_errorPrototype);
131     JSValueUnprotect(m_context, m_functionConstructor);
132     JSValueUnprotect(m_context, m_functionPrototype);
133     JSValueUnprotect(m_context, m_dateConstructor);
134     JSValueUnprotect(m_context, m_datePrototype);
135     JSValueUnprotect(m_context, m_hasOwnPropertyFunction);
136     JSValueUnprotect(m_context, m_getOwnPropertyNamesFunction);
137     JSGlobalContextRelease(m_context);
138 }
139
140 inline bool QScriptOriginalGlobalObject::objectHasOwnProperty(JSObjectRef object, JSStringRef property) const
141 {
142     // FIXME This function should be replaced by JSC C API.
143     JSValueRef exception = 0;
144     JSValueRef propertyName[] = { JSValueMakeString(m_context, property) };
145     JSValueRef result = JSObjectCallAsFunction(m_context, m_hasOwnPropertyFunction, object, 1, propertyName, &exception);
146     return exception ? false : JSValueToBoolean(m_context, result);
147 }
148
149 /*!
150     \internal
151     This method gives ownership of all JSStringRefs.
152 */
153 inline QVector<JSStringRef> QScriptOriginalGlobalObject::objectGetOwnPropertyNames(JSObjectRef object) const
154 {
155     JSValueRef exception = 0;
156     JSObjectRef propertyNames
157             = const_cast<JSObjectRef>(JSObjectCallAsFunction(m_context,
158                                                             m_getOwnPropertyNamesFunction,
159                                                             /* thisObject */ 0,
160                                                             /* argumentCount */ 1,
161                                                             &object,
162                                                             &exception));
163     Q_ASSERT(JSValueIsObject(m_context, propertyNames));
164     Q_ASSERT(!exception);
165     JSStringRef lengthName = QScriptConverter::toString("length");
166     int count = JSValueToNumber(m_context, JSObjectGetProperty(m_context, propertyNames, lengthName, &exception), &exception);
167
168     Q_ASSERT(!exception);
169     QVector<JSStringRef> names;
170     names.reserve(count);
171     for (int i = 0; i < count; ++i) {
172         JSValueRef tmp = JSObjectGetPropertyAtIndex(m_context, propertyNames, i, &exception);
173         names.append(JSValueToStringCopy(m_context, tmp, &exception));
174         Q_ASSERT(!exception);
175     }
176     return names;
177 }
178
179 inline bool QScriptOriginalGlobalObject::isDate(JSValueRef value) const
180 {
181     return isType(value, m_dateConstructor, m_datePrototype);
182 }
183
184 inline bool QScriptOriginalGlobalObject::isArray(JSValueRef value) const
185 {
186     return isType(value, m_arrayConstructor, m_arrayPrototype);
187 }
188
189 inline bool QScriptOriginalGlobalObject::isError(JSValueRef value) const
190 {
191     return isType(value, m_errorConstructor, m_errorPrototype);
192 }
193
194 inline JSValueRef QScriptOriginalGlobalObject::functionPrototype() const
195 {
196     return m_functionPrototype;
197 }
198
199 inline bool QScriptOriginalGlobalObject::isType(JSValueRef value, JSObjectRef constructor, JSValueRef prototype) const
200 {
201     // JSC API doesn't export the [[Class]] information for the builtins. But we know that a value
202     // is an object of the Type if it was created with the Type constructor or if it is the Type.prototype.
203     JSValueRef exception = 0;
204     bool result = JSValueIsInstanceOfConstructor(m_context, value, constructor, &exception) || JSValueIsStrictEqual(m_context, value, prototype);
205     Q_ASSERT(!exception);
206     return result;
207 }
208
209 #endif // qscriptoriginalglobalobject_p_h