1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qv8contextwrapper_p.h"
43 #include "qv8engine_p.h"
45 #include <private/qdeclarativeengine_p.h>
46 #include <private/qdeclarativecontext_p.h>
50 static QString internal(QLatin1String("You've stumbled onto an internal implementation detail "
51 "that should never have been exposed."));
53 class QV8ContextResource : public QV8ObjectResource
55 V8_RESOURCE_TYPE(ContextType);
58 QV8ContextResource(QV8Engine *engine, QDeclarativeContextData *context, QObject *scopeObject);
59 ~QV8ContextResource();
61 inline QDeclarativeContextData *getContext() const;
63 QDeclarativeGuard<QObject> scopeObject;
65 quint32 hasSubContexts:1;
66 quint32 ownsContext:1;
70 QObject *secondaryScope;
72 // XXX aakenned - this is somewhat of a horrible abuse of external strings :)
73 struct SubContext : public v8::String::ExternalStringResource {
74 SubContext(QDeclarativeContextData *context) : context(context) {}
75 QDeclarativeGuardedContextData context;
77 virtual const uint16_t* data() const { return (const uint16_t *)internal.constData(); }
78 virtual size_t length() const { return internal.length(); }
82 QDeclarativeGuardedContextData context;
85 QV8ContextResource::QV8ContextResource(QV8Engine *engine, QDeclarativeContextData *context, QObject *scopeObject)
86 : QV8ObjectResource(engine), scopeObject(scopeObject), hasSubContexts(false), ownsContext(false),
87 readOnly(true), secondaryScope(0), context(context)
91 QV8ContextResource::~QV8ContextResource()
93 if (ownsContext && context)
97 // Returns the context, including resolving a subcontext
98 QDeclarativeContextData *QV8ContextResource::getContext() const
103 v8::Local<v8::Value> callingdata = v8::Context::GetCallingScriptData();
104 if (callingdata.IsEmpty() || !callingdata->IsString())
107 v8::Local<v8::String> callingstring = callingdata->ToString();
108 Q_ASSERT(callingstring->IsExternal());
109 Q_ASSERT(callingstring->GetExternalStringResource());
111 SubContext *sc = static_cast<SubContext *>(callingstring->GetExternalStringResource());
115 QV8ContextWrapper::QV8ContextWrapper()
120 QV8ContextWrapper::~QV8ContextWrapper()
124 void QV8ContextWrapper::destroy()
126 qPersistentDispose(m_urlConstructor);
127 qPersistentDispose(m_constructor);
130 void QV8ContextWrapper::init(QV8Engine *engine)
134 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
135 ft->InstanceTemplate()->SetHasExternalResource(true);
136 ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
137 m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
140 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
141 ft->InstanceTemplate()->SetHasExternalResource(true);
142 ft->InstanceTemplate()->SetFallbackPropertyHandler(NullGetter, NullSetter);
143 m_urlConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
147 v8::Local<v8::Object> QV8ContextWrapper::qmlScope(QDeclarativeContextData *ctxt, QObject *scope)
149 // XXX aakenned - NewInstance() is slow for our case
150 v8::Local<v8::Object> rv = m_constructor->NewInstance();
151 QV8ContextResource *r = new QV8ContextResource(m_engine, ctxt, scope);
152 rv->SetExternalResource(r);
156 v8::Local<v8::Object> QV8ContextWrapper::urlScope(const QUrl &url)
158 QDeclarativeContextData *context = new QDeclarativeContextData;
160 context->isInternal = true;
161 context->isJSContext = true;
163 // XXX aakenned - NewInstance() is slow for our case
164 v8::Local<v8::Object> rv = m_urlConstructor->NewInstance();
165 QV8ContextResource *r = new QV8ContextResource(m_engine, context, 0);
166 r->ownsContext = true;
167 rv->SetExternalResource(r);
171 void QV8ContextWrapper::setReadOnly(v8::Handle<v8::Object> qmlglobal, bool readOnly)
173 QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(qmlglobal);
175 resource->readOnly = readOnly;
178 void QV8ContextWrapper::addSubContext(v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Script> script,
179 QDeclarativeContextData *ctxt)
181 QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(qmlglobal);
183 resource->hasSubContexts = true;
184 script->SetData(v8::String::NewExternal(new QV8ContextResource::SubContext(ctxt)));
187 QObject *QV8ContextWrapper::setSecondaryScope(v8::Handle<v8::Object> ctxt, QObject *scope)
189 QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(ctxt);
190 if (!resource) return 0;
192 QObject *rv = resource->secondaryScope;
193 resource->secondaryScope = scope;
197 QDeclarativeContextData *QV8ContextWrapper::callingContext()
199 v8::Local<v8::Object> qmlglobal = v8::Context::GetCallingQmlGlobal();
200 if (qmlglobal.IsEmpty()) return 0;
202 QV8ContextResource *r = v8_resource_cast<QV8ContextResource>(qmlglobal);
203 return r?r->getContext():0;
206 QDeclarativeContextData *QV8ContextWrapper::context(v8::Handle<v8::Value> value)
208 if (!value->IsObject())
211 v8::Handle<v8::Object> qmlglobal = v8::Handle<v8::Object>::Cast(value);
212 QV8ContextResource *r = v8_resource_cast<QV8ContextResource>(qmlglobal);
213 return r?r->getContext():0;
216 v8::Handle<v8::Value> QV8ContextWrapper::NullGetter(v8::Local<v8::String> property,
217 const v8::AccessorInfo &info)
219 QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
222 return v8::Undefined(); // XXX Should we throw here?
224 QV8Engine *engine = resource->engine;
226 QString error = QLatin1String("Can't find variable: ") + engine->toString(property);
227 v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
228 return v8::Undefined();
231 v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
232 const v8::AccessorInfo &info)
234 QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
237 return v8::Undefined(); // XXX Should we throw here?
239 // XXX aakenned too agressive
240 QDeclarativeContextData *context = resource->getContext();
243 return v8::Undefined(); // XXX Should we throw here?
245 // Search type (attached property/enum/imported scripts) names
246 // Secondary scope object
248 // Search context properties
249 // Search scope object
250 // Search context object
251 // context = context->parent
254 QV8Engine *engine = resource->engine;
255 QObject *scopeObject = resource->scopeObject;
257 if (context->imports && QV8Engine::startsWithUpper(property)) {
258 // Search for attached properties, enums and imported scripts
259 QDeclarativeTypeNameCache::Data *data = context->imports->data(property);
262 if (data->importedScriptIndex != -1) {
263 int index = data->importedScriptIndex;
264 if (index < context->importedScripts.count())
265 return context->importedScripts.at(index);
267 return v8::Undefined();
268 } else if (data->type) {
269 return engine->typeWrapper()->newObject(scopeObject, data->type);
270 } else if (data->typeNamespace) {
271 return engine->typeWrapper()->newObject(scopeObject, data->typeNamespace);
273 Q_ASSERT(!"Unreachable");
279 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
280 QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
282 if (resource->secondaryScope) {
283 v8::Handle<v8::Value> result = qobjectWrapper->getProperty(resource->secondaryScope, property,
284 QV8QObjectWrapper::IgnoreRevision);
285 if (!result.IsEmpty()) return result;
289 // Search context properties
290 if (context->propertyNames) {
291 int propertyIdx = context->propertyNames->value(property);
293 if (propertyIdx != -1) {
294 typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty;
296 if (propertyIdx < context->idValueCount) {
298 if (ep->captureProperties)
299 ep->capturedProperties << CapturedProperty(&context->idValues[propertyIdx].bindings);
301 return engine->newQObject(context->idValues[propertyIdx]);
304 QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
306 if (ep->captureProperties)
307 ep->capturedProperties << CapturedProperty(context->asQDeclarativeContext(), -1,
308 propertyIdx + cp->notifyIndex);
310 const QVariant &value = cp->propertyValues.at(propertyIdx);
311 if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
312 QDeclarativeListProperty<QObject> prop(context->asQDeclarativeContext(), (void*)propertyIdx,
314 QDeclarativeContextPrivate::context_count,
315 QDeclarativeContextPrivate::context_at);
316 return engine->listWrapper()->newList(prop, qMetaTypeId<QDeclarativeListProperty<QObject> >());
318 return engine->fromVariant(cp->propertyValues.at(propertyIdx));
324 // Search scope object
326 v8::Handle<v8::Value> result = qobjectWrapper->getProperty(scopeObject, property,
327 QV8QObjectWrapper::CheckRevision);
328 if (!result.IsEmpty()) return result;
333 // Search context object
334 if (context->contextObject) {
335 v8::Handle<v8::Value> result = qobjectWrapper->getProperty(context->contextObject, property,
336 QV8QObjectWrapper::CheckRevision);
337 if (!result.IsEmpty()) return result;
340 context = context->parent;
343 QString error = QLatin1String("Can't find variable: ") + engine->toString(property);
344 v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
345 return v8::Undefined();
348 v8::Handle<v8::Value> QV8ContextWrapper::NullSetter(v8::Local<v8::String> property,
349 v8::Local<v8::Value>,
350 const v8::AccessorInfo &info)
352 QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
355 return v8::Undefined(); // XXX Should we throw here?
357 QV8Engine *engine = resource->engine;
359 if (!resource->readOnly) {
360 return v8::Handle<v8::Value>();
362 QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) +
364 v8::ThrowException(v8::Exception::Error(engine->toString(error)));
365 return v8::Undefined();
369 v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property,
370 v8::Local<v8::Value> value,
371 const v8::AccessorInfo &info)
373 QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
376 return v8::Undefined(); // XXX Should we throw here?
378 // XXX aakenned too agressive
379 QDeclarativeContextData *context = resource->getContext();
382 return v8::Undefined(); // XXX Should we throw here?
384 // See QV8ContextWrapper::Getter for resolution order
386 QV8Engine *engine = resource->engine;
387 QObject *scopeObject = resource->scopeObject;
389 QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
391 // Search scope object
392 if (resource->secondaryScope && qobjectWrapper->setProperty(resource->secondaryScope, property, value,
393 QV8QObjectWrapper::IgnoreRevision))
397 // Search context properties
398 if (context->propertyNames && -1 != context->propertyNames->value(property))
401 // Search scope object
403 qobjectWrapper->setProperty(scopeObject, property, value, QV8QObjectWrapper::CheckRevision))
407 // Search context object
408 if (context->contextObject &&
409 qobjectWrapper->setProperty(context->contextObject, property, value, QV8QObjectWrapper::CheckRevision))
412 context = context->parent;
415 if (!resource->readOnly) {
416 return v8::Handle<v8::Value>();
418 QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) +
420 v8::ThrowException(v8::Exception::Error(engine->toString(error)));
421 return v8::Undefined();