source: trunk/src/script/bridge/qscriptclassobject.cpp@ 1028

Last change on this file since 1028 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 11.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtScript module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL-ONLY$
10** GNU Lesser General Public License Usage
11** This file may be used under the terms of the GNU Lesser
12** General Public License version 2.1 as published by the Free Software
13** Foundation and appearing in the file LICENSE.LGPL included in the
14** packaging of this file. Please review the following information to
15** ensure the GNU Lesser General Public License version 2.1 requirements
16** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17**
18** If you have questions regarding the use of this file, please contact
19** Nokia at [email protected].
20** $QT_END_LICENSE$
21**
22****************************************************************************/
23
24#include "config.h"
25#include "qscriptclassobject_p.h"
26
27#include "../api/qscriptengine.h"
28#include "../api/qscriptengine_p.h"
29#include "../api/qscriptcontext.h"
30#include "../api/qscriptcontext_p.h"
31#include "../api/qscriptclass.h"
32#include "../api/qscriptclasspropertyiterator.h"
33
34#include "Error.h"
35#include "PropertyNameArray.h"
36
37Q_DECLARE_METATYPE(QScriptContext*)
38Q_DECLARE_METATYPE(QScriptValue)
39Q_DECLARE_METATYPE(QScriptValueList)
40
41QT_BEGIN_NAMESPACE
42
43namespace QScript
44{
45
46ClassObjectDelegate::ClassObjectDelegate(QScriptClass *scriptClass)
47 : m_scriptClass(scriptClass)
48{
49}
50
51ClassObjectDelegate::~ClassObjectDelegate()
52{
53}
54
55QScriptObjectDelegate::Type ClassObjectDelegate::type() const
56{
57 return ClassObject;
58}
59
60bool ClassObjectDelegate::getOwnPropertySlot(QScriptObject* object,
61 JSC::ExecState *exec,
62 const JSC::Identifier &propertyName,
63 JSC::PropertySlot &slot)
64{
65 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
66 QScript::SaveFrameHelper saveFrame(engine, exec);
67 // for compatibility with the old back-end, normal JS properties
68 // are queried first.
69 if (QScriptObjectDelegate::getOwnPropertySlot(object, exec, propertyName, slot))
70 return true;
71
72 QScriptValue scriptObject = engine->scriptValueFromJSCValue(object);
73 QScriptString scriptName;
74 QScriptStringPrivate scriptName_d(engine, propertyName, QScriptStringPrivate::StackAllocated);
75 QScriptStringPrivate::init(scriptName, &scriptName_d);
76 uint id = 0;
77 QScriptClass::QueryFlags flags = m_scriptClass->queryProperty(
78 scriptObject, scriptName, QScriptClass::HandlesReadAccess, &id);
79 if (flags & QScriptClass::HandlesReadAccess) {
80 QScriptValue value = m_scriptClass->property(scriptObject, scriptName, id);
81 if (!value.isValid()) {
82 // The class claims to have the property, but returned an invalid
83 // value. Silently convert to undefined to avoid the invalid value
84 // "escaping" into JS.
85 value = QScriptValue(QScriptValue::UndefinedValue);
86 }
87 slot.setValue(engine->scriptValueToJSCValue(value));
88 return true;
89 }
90 return false;
91}
92
93bool ClassObjectDelegate::getOwnPropertyDescriptor(QScriptObject *object,
94 JSC::ExecState *exec,
95 const JSC::Identifier &propertyName,
96 JSC::PropertyDescriptor &descriptor)
97{
98 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
99 QScript::SaveFrameHelper saveFrame(engine, exec);
100 // for compatibility with the old back-end, normal JS properties
101 // are queried first.
102 if (QScriptObjectDelegate::getOwnPropertyDescriptor(object, exec, propertyName, descriptor))
103 return true;
104
105 QScriptValue scriptObject = engine->scriptValueFromJSCValue(object);
106 QScriptString scriptName;
107 QScriptStringPrivate scriptName_d(engine, propertyName, QScriptStringPrivate::StackAllocated);
108 QScriptStringPrivate::init(scriptName, &scriptName_d);
109 uint id = 0;
110 QScriptClass::QueryFlags qflags = m_scriptClass->queryProperty(
111 scriptObject, scriptName, QScriptClass::HandlesReadAccess, &id);
112 if (qflags & QScriptClass::HandlesReadAccess) {
113 QScriptValue::PropertyFlags pflags = m_scriptClass->propertyFlags(scriptObject, scriptName, id);
114 unsigned attribs = 0;
115 if (pflags & QScriptValue::ReadOnly)
116 attribs |= JSC::ReadOnly;
117 if (pflags & QScriptValue::SkipInEnumeration)
118 attribs |= JSC::DontEnum;
119 if (pflags & QScriptValue::Undeletable)
120 attribs |= JSC::DontDelete;
121 if (pflags & QScriptValue::PropertyGetter)
122 attribs |= JSC::Getter;
123 if (pflags & QScriptValue::PropertySetter)
124 attribs |= JSC::Setter;
125 attribs |= pflags & QScriptValue::UserRange;
126 // Rather than calling the getter, we could return an access descriptor here.
127 QScriptValue value = m_scriptClass->property(scriptObject, scriptName, id);
128 if (!value.isValid()) {
129 // The class claims to have the property, but returned an invalid
130 // value. Silently convert to undefined to avoid the invalid value
131 // "escaping" into JS.
132 value = QScriptValue(QScriptValue::UndefinedValue);
133 }
134 descriptor.setDescriptor(engine->scriptValueToJSCValue(value), attribs);
135 return true;
136 }
137 return false;
138}
139
140void ClassObjectDelegate::put(QScriptObject* object, JSC::ExecState *exec,
141 const JSC::Identifier &propertyName,
142 JSC::JSValue value, JSC::PutPropertySlot &slot)
143{
144 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
145 QScript::SaveFrameHelper saveFrame(engine, exec);
146 QScriptValue scriptObject = engine->scriptValueFromJSCValue(object);
147 QScriptString scriptName;
148 QScriptStringPrivate scriptName_d(engine, propertyName, QScriptStringPrivate::StackAllocated);
149 QScriptStringPrivate::init(scriptName, &scriptName_d);
150 uint id = 0;
151 QScriptClass::QueryFlags flags = m_scriptClass->queryProperty(
152 scriptObject, scriptName, QScriptClass::HandlesWriteAccess, &id);
153 if (flags & QScriptClass::HandlesWriteAccess) {
154 m_scriptClass->setProperty(scriptObject, scriptName, id, engine->scriptValueFromJSCValue(value));
155 return;
156 }
157 QScriptObjectDelegate::put(object, exec, propertyName, value, slot);
158}
159
160bool ClassObjectDelegate::deleteProperty(QScriptObject* object, JSC::ExecState *exec,
161 const JSC::Identifier &propertyName)
162{
163 // ### avoid duplication of put()
164 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
165 QScript::SaveFrameHelper saveFrame(engine, exec);
166 QScriptValue scriptObject = engine->scriptValueFromJSCValue(object);
167 QScriptString scriptName;
168 QScriptStringPrivate scriptName_d(engine, propertyName, QScriptStringPrivate::StackAllocated);
169 QScriptStringPrivate::init(scriptName, &scriptName_d);
170 uint id = 0;
171 QScriptClass::QueryFlags flags = m_scriptClass->queryProperty(
172 scriptObject, scriptName, QScriptClass::HandlesWriteAccess, &id);
173 if (flags & QScriptClass::HandlesWriteAccess) {
174 if (m_scriptClass->propertyFlags(scriptObject, scriptName, id) & QScriptValue::Undeletable)
175 return false;
176 m_scriptClass->setProperty(scriptObject, scriptName, id, QScriptValue());
177 return true;
178 }
179 return QScriptObjectDelegate::deleteProperty(object, exec, propertyName);
180}
181
182void ClassObjectDelegate::getOwnPropertyNames(QScriptObject* object, JSC::ExecState *exec,
183 JSC::PropertyNameArray &propertyNames,
184 JSC::EnumerationMode mode)
185{
186 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
187 QScript::SaveFrameHelper saveFrame(engine, exec);
188 QScriptValue scriptObject = engine->scriptValueFromJSCValue(object);
189 QScriptClassPropertyIterator *it = m_scriptClass->newIterator(scriptObject);
190 if (it != 0) {
191 while (it->hasNext()) {
192 it->next();
193 QString name = it->name().toString();
194 propertyNames.add(JSC::Identifier(exec, name));
195 }
196 delete it;
197 }
198 QScriptObjectDelegate::getOwnPropertyNames(object, exec, propertyNames, mode);
199}
200
201JSC::CallType ClassObjectDelegate::getCallData(QScriptObject*, JSC::CallData &callData)
202{
203 if (!m_scriptClass->supportsExtension(QScriptClass::Callable))
204 return JSC::CallTypeNone;
205 callData.native.function = call;
206 return JSC::CallTypeHost;
207}
208
209JSC::JSValue JSC_HOST_CALL ClassObjectDelegate::call(JSC::ExecState *exec, JSC::JSObject *callee,
210 JSC::JSValue thisValue, const JSC::ArgList &args)
211{
212 if (!callee->inherits(&QScriptObject::info))
213 return JSC::throwError(exec, JSC::TypeError, "callee is not a ClassObject object");
214 QScriptObject *obj = static_cast<QScriptObject*>(callee);
215 QScriptObjectDelegate *delegate = obj->delegate();
216 if (!delegate || (delegate->type() != QScriptObjectDelegate::ClassObject))
217 return JSC::throwError(exec, JSC::TypeError, "callee is not a ClassObject object");
218
219 QScriptClass *scriptClass = static_cast<ClassObjectDelegate*>(delegate)->scriptClass();
220 QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
221
222 JSC::ExecState *oldFrame = eng_p->currentFrame;
223 eng_p->pushContext(exec, thisValue, args, callee);
224 QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame);
225 QScriptValue scriptObject = eng_p->scriptValueFromJSCValue(obj);
226 QVariant result = scriptClass->extension(QScriptClass::Callable, qVariantFromValue(ctx));
227 eng_p->popContext();
228 eng_p->currentFrame = oldFrame;
229 return QScriptEnginePrivate::jscValueFromVariant(exec, result);
230}
231
232JSC::ConstructType ClassObjectDelegate::getConstructData(QScriptObject*, JSC::ConstructData &constructData)
233{
234 if (!m_scriptClass->supportsExtension(QScriptClass::Callable))
235 return JSC::ConstructTypeNone;
236 constructData.native.function = construct;
237 return JSC::ConstructTypeHost;
238}
239
240JSC::JSObject* ClassObjectDelegate::construct(JSC::ExecState *exec, JSC::JSObject *callee,
241 const JSC::ArgList &args)
242{
243 Q_ASSERT(callee->inherits(&QScriptObject::info));
244 QScriptObject *obj = static_cast<QScriptObject*>(callee);
245 QScriptObjectDelegate *delegate = obj->delegate();
246 QScriptClass *scriptClass = static_cast<ClassObjectDelegate*>(delegate)->scriptClass();
247
248 QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
249 JSC::ExecState *oldFrame = eng_p->currentFrame;
250 eng_p->pushContext(exec, JSC::JSValue(), args, callee, true);
251 QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame);
252
253 QScriptValue defaultObject = ctx->thisObject();
254 QScriptValue result = qvariant_cast<QScriptValue>(scriptClass->extension(QScriptClass::Callable, qVariantFromValue(ctx)));
255 if (!result.isObject())
256 result = defaultObject;
257 eng_p->popContext();
258 eng_p->currentFrame = oldFrame;
259 return JSC::asObject(eng_p->scriptValueToJSCValue(result));
260}
261
262bool ClassObjectDelegate::hasInstance(QScriptObject* object, JSC::ExecState *exec,
263 JSC::JSValue value, JSC::JSValue proto)
264{
265 if (!scriptClass()->supportsExtension(QScriptClass::HasInstance))
266 return QScriptObjectDelegate::hasInstance(object, exec, value, proto);
267 QScriptValueList args;
268 QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
269 QScript::SaveFrameHelper saveFrame(eng_p, exec);
270 args << eng_p->scriptValueFromJSCValue(object) << eng_p->scriptValueFromJSCValue(value);
271 QVariant result = scriptClass()->extension(QScriptClass::HasInstance, qVariantFromValue(args));
272 return result.toBool();
273}
274
275} // namespace QScript
276
277QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.