Implement strict mode for qmldir modules
[profile/ivi/qtdeclarative.git] / src / qml / qml / qquickworkerscript.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickworkerscript_p.h"
43 #include "qquicklistmodel_p.h"
44 #include "qquicklistmodelworkeragent_p.h"
45 #include "qqmlengine_p.h"
46 #include "qqmlexpression_p.h"
47
48 #include <QtCore/qcoreevent.h>
49 #include <QtCore/qcoreapplication.h>
50 #include <QtCore/qdebug.h>
51 #include <QtQml/qjsengine.h>
52 #include <QtCore/qmutex.h>
53 #include <QtCore/qwaitcondition.h>
54 #include <QtCore/qfile.h>
55 #include <QtCore/qdatetime.h>
56 #include <QtNetwork/qnetworkaccessmanager.h>
57 #include <QtQml/qqmlinfo.h>
58 #include <QtQml/qqmlfile.h>
59 #include "qqmlnetworkaccessmanagerfactory.h"
60
61 #include <private/qv8engine_p.h>
62 #include <private/qv8worker_p.h>
63
64 QT_BEGIN_NAMESPACE
65
66 class WorkerDataEvent : public QEvent
67 {
68 public:
69     enum Type { WorkerData = QEvent::User };
70
71     WorkerDataEvent(int workerId, const QByteArray &data);
72     virtual ~WorkerDataEvent();
73
74     int workerId() const;
75     QByteArray data() const;
76
77 private:
78     int m_id;
79     QByteArray m_data;
80 };
81
82 class WorkerLoadEvent : public QEvent
83 {
84 public:
85     enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 };
86
87     WorkerLoadEvent(int workerId, const QUrl &url);
88
89     int workerId() const;
90     QUrl url() const;
91
92 private:
93     int m_id;
94     QUrl m_url;
95 };
96
97 class WorkerRemoveEvent : public QEvent
98 {
99 public:
100     enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 };
101
102     WorkerRemoveEvent(int workerId);
103
104     int workerId() const;
105
106 private:
107     int m_id;
108 };
109
110 class WorkerErrorEvent : public QEvent
111 {
112 public:
113     enum Type { WorkerError = WorkerRemoveEvent::WorkerRemove + 1 };
114
115     WorkerErrorEvent(const QQmlError &error);
116
117     QQmlError error() const;
118
119 private:
120     QQmlError m_error;
121 };
122
123 class QQuickWorkerScriptEnginePrivate : public QObject
124 {
125     Q_OBJECT
126 public:
127     enum WorkerEventTypes {
128         WorkerDestroyEvent = QEvent::User + 100
129     };
130
131     QQuickWorkerScriptEnginePrivate(QQmlEngine *eng);
132
133     class WorkerEngine : public QV8Engine
134     {
135     public:
136         WorkerEngine(QQuickWorkerScriptEnginePrivate *parent);
137         ~WorkerEngine();
138
139         void init();
140         virtual QNetworkAccessManager *networkAccessManager();
141
142         QQuickWorkerScriptEnginePrivate *p;
143
144         v8::Local<v8::Function> sendFunction(int id);
145         void callOnMessage(v8::Handle<v8::Object> object, v8::Handle<v8::Value> arg);
146     private:
147         v8::Persistent<v8::Function> onmessage;
148         v8::Persistent<v8::Function> createsend;
149         QNetworkAccessManager *accessManager;
150     };
151
152     WorkerEngine *workerEngine;
153     static QQuickWorkerScriptEnginePrivate *get(QV8Engine *e) {
154         return static_cast<WorkerEngine *>(e)->p;
155     }
156
157     QQmlEngine *qmlengine;
158
159     QMutex m_lock;
160     QWaitCondition m_wait;
161
162     struct WorkerScript {
163         WorkerScript();
164         ~WorkerScript();
165
166         int id;
167         QUrl source;
168         bool initialized;
169         QQuickWorkerScript *owner;
170         v8::Persistent<v8::Object> object;
171     };
172
173     QHash<int, WorkerScript *> workers;
174     v8::Handle<v8::Object> getWorker(WorkerScript *);
175
176     int m_nextId;
177
178     static v8::Handle<v8::Value> sendMessage(const v8::Arguments &args);
179
180 signals:
181     void stopThread();
182
183 protected:
184     virtual bool event(QEvent *);
185
186 private:
187     void processMessage(int, const QByteArray &);
188     void processLoad(int, const QUrl &);
189     void reportScriptException(WorkerScript *, const QQmlError &error);
190 };
191
192 QQuickWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QQuickWorkerScriptEnginePrivate *parent) 
193 : QV8Engine(0), p(parent), accessManager(0)
194 {
195 }
196
197 QQuickWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine() 
198
199     qPersistentDispose(createsend);
200     qPersistentDispose(onmessage);
201     delete accessManager; 
202 }
203
204 void QQuickWorkerScriptEnginePrivate::WorkerEngine::init()
205 {
206     initQmlGlobalObject();
207 #define CALL_ONMESSAGE_SCRIPT \
208     "(function(object, message) { "\
209         "var isfunction = false; "\
210         "try { "\
211             "isfunction = object.WorkerScript.onMessage instanceof Function; "\
212         "} catch (e) {}" \
213         "if (isfunction) "\
214             "object.WorkerScript.onMessage(message); "\
215     "})"
216
217 #define SEND_MESSAGE_CREATE_SCRIPT \
218     "(function(method, engine) { "\
219         "return (function(id) { "\
220             "return (function(message) { "\
221                 "if (arguments.length) method(engine, id, message); "\
222             "}); "\
223         "}); "\
224     "})"
225
226     v8::HandleScope handle_scope;
227     v8::Context::Scope scope(context());
228
229     {
230     v8::Local<v8::Script> onmessagescript = v8::Script::New(v8::String::New(CALL_ONMESSAGE_SCRIPT));
231     onmessage = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(onmessagescript->Run()));
232     }
233     {
234     v8::Local<v8::Script> createsendscript = v8::Script::New(v8::String::New(SEND_MESSAGE_CREATE_SCRIPT));
235     v8::Local<v8::Function> createsendconstructor = v8::Local<v8::Function>::Cast(createsendscript->Run());
236
237     v8::Handle<v8::Value> args[] = { 
238         V8FUNCTION(QQuickWorkerScriptEnginePrivate::sendMessage, this)
239     };
240     v8::Local<v8::Value> createsendvalue = createsendconstructor->Call(global(), 1, args);
241     
242     createsend = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(createsendvalue));
243     }
244 }
245
246 // Requires handle and context scope
247 v8::Local<v8::Function> QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(int id)
248 {
249     v8::Handle<v8::Value> args[] = { v8::Integer::New(id) };
250     return v8::Local<v8::Function>::Cast(createsend->Call(global(), 1, args));
251 }
252
253 // Requires handle and context scope
254 void QQuickWorkerScriptEnginePrivate::WorkerEngine::callOnMessage(v8::Handle<v8::Object> object, 
255                                                                         v8::Handle<v8::Value> arg)
256 {
257     v8::Handle<v8::Value> args[] = { object, arg };
258     onmessage->Call(global(), 2, args);
259 }
260
261 QNetworkAccessManager *QQuickWorkerScriptEnginePrivate::WorkerEngine::networkAccessManager() 
262 {
263     if (!accessManager) {
264         if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
265             accessManager = p->qmlengine->networkAccessManagerFactory()->create(p);
266         } else {
267             accessManager = new QNetworkAccessManager(p);
268         }
269     }
270     return accessManager;
271 }
272
273 QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *engine)
274 : workerEngine(0), qmlengine(engine), m_nextId(0)
275 {
276 }
277
278 v8::Handle<v8::Value> QQuickWorkerScriptEnginePrivate::sendMessage(const v8::Arguments &args)
279 {
280     WorkerEngine *engine = (WorkerEngine*)V8ENGINE();
281
282     int id = args[1]->Int32Value();
283
284     QByteArray data = QV8Worker::serialize(args[2], engine);
285
286     QMutexLocker locker(&engine->p->m_lock);
287     WorkerScript *script = engine->p->workers.value(id);
288     if (!script)
289         return v8::Undefined();
290
291     if (script->owner)
292         QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data));
293
294     return v8::Undefined();
295 }
296
297 // Requires handle scope and context scope
298 v8::Handle<v8::Object> QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *script)
299 {
300     if (!script->initialized) {
301         script->initialized = true;
302
303         script->object = qPersistentNew<v8::Object>(workerEngine->contextWrapper()->urlScope(script->source));
304
305         workerEngine->contextWrapper()->setReadOnly(script->object, false);
306
307         v8::Local<v8::Object> api = v8::Object::New();
308         api->Set(v8::String::New("sendMessage"), workerEngine->sendFunction(script->id));
309
310         script->object->Set(v8::String::New("WorkerScript"), api);
311
312         workerEngine->contextWrapper()->setReadOnly(script->object, true);
313     }
314
315     return script->object;
316 }
317
318 bool QQuickWorkerScriptEnginePrivate::event(QEvent *event)
319 {
320     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
321         WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
322         processMessage(workerEvent->workerId(), workerEvent->data());
323         return true;
324     } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
325         WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
326         processLoad(workerEvent->workerId(), workerEvent->url());
327         return true;
328     } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) {
329         emit stopThread();
330         return true;
331     } else if (event->type() == (QEvent::Type)WorkerRemoveEvent::WorkerRemove) {
332         WorkerRemoveEvent *workerEvent = static_cast<WorkerRemoveEvent *>(event);
333         workers.remove(workerEvent->workerId());
334         return true;
335     } else {
336         return QObject::event(event);
337     }
338 }
339
340 void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &data)
341 {
342     WorkerScript *script = workers.value(id);
343     if (!script)
344         return;
345
346     v8::HandleScope handle_scope;
347     v8::Context::Scope scope(workerEngine->context());
348
349     v8::Handle<v8::Value> value = QV8Worker::deserialize(data, workerEngine);
350
351     v8::TryCatch tc;
352     workerEngine->callOnMessage(script->object, value);
353
354     if (tc.HasCaught()) {
355         QQmlError error;
356         QQmlExpressionPrivate::exceptionToError(tc.Message(), error);
357         reportScriptException(script, error);
358     }
359 }
360
361 void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
362 {
363     if (url.isRelative())
364         return;
365
366     QString fileName = QQmlFile::urlToLocalFileOrQrc(url);
367
368     QFile f(fileName);
369     if (f.open(QIODevice::ReadOnly)) {
370         QByteArray data = f.readAll();
371         QString sourceCode = QString::fromUtf8(data);
372         QQmlScript::Parser::extractPragmas(sourceCode);
373
374         v8::HandleScope handle_scope;
375         v8::Context::Scope scope(workerEngine->context());
376
377         WorkerScript *script = workers.value(id);
378         if (!script)
379             return;
380         script->source = url;
381         v8::Handle<v8::Object> activation = getWorker(script);
382         if (activation.IsEmpty())
383             return;
384
385         // XXX ???
386         // workerEngine->baseUrl = url;
387
388         v8::TryCatch tc;
389         v8::Local<v8::Script> program = workerEngine->qmlModeCompile(sourceCode, url.toString());
390
391         if (!tc.HasCaught()) 
392             program->Run(activation);
393         
394         if (tc.HasCaught()) {
395             QQmlError error;
396             QQmlExpressionPrivate::exceptionToError(tc.Message(), error);
397             reportScriptException(script, error);
398         }
399     } else {
400         qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
401     }
402 }
403
404 void QQuickWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script, 
405                                                                   const QQmlError &error)
406 {
407     QQuickWorkerScriptEnginePrivate *p = QQuickWorkerScriptEnginePrivate::get(workerEngine);
408
409     QMutexLocker locker(&p->m_lock);
410     if (script->owner)
411         QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
412 }
413
414 WorkerDataEvent::WorkerDataEvent(int workerId, const QByteArray &data)
415 : QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
416 {
417 }
418
419 WorkerDataEvent::~WorkerDataEvent()
420 {
421 }
422
423 int WorkerDataEvent::workerId() const
424 {
425     return m_id;
426 }
427
428 QByteArray WorkerDataEvent::data() const
429 {
430     return m_data;
431 }
432
433 WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
434 : QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url)
435 {
436 }
437
438 int WorkerLoadEvent::workerId() const
439 {
440     return m_id;
441 }
442
443 QUrl WorkerLoadEvent::url() const
444 {
445     return m_url;
446 }
447
448 WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
449 : QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
450 {
451 }
452
453 int WorkerRemoveEvent::workerId() const
454 {
455     return m_id;
456 }
457
458 WorkerErrorEvent::WorkerErrorEvent(const QQmlError &error)
459 : QEvent((QEvent::Type)WorkerError), m_error(error)
460 {
461 }
462
463 QQmlError WorkerErrorEvent::error() const
464 {
465     return m_error;
466 }
467
468 QQuickWorkerScriptEngine::QQuickWorkerScriptEngine(QQmlEngine *parent)
469 : QThread(parent), d(new QQuickWorkerScriptEnginePrivate(parent))
470 {
471     d->m_lock.lock();
472     connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection);
473     start(QThread::LowestPriority);
474     d->m_wait.wait(&d->m_lock);
475     d->moveToThread(this);
476     d->m_lock.unlock();
477 }
478
479 QQuickWorkerScriptEngine::~QQuickWorkerScriptEngine()
480 {
481     d->m_lock.lock();
482     QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QQuickWorkerScriptEnginePrivate::WorkerDestroyEvent));
483     d->m_lock.unlock();
484
485     //We have to force to cleanup the main thread's event queue here
486     //to make sure the main GUI release all pending locks/wait conditions which
487     //some worker script/agent are waiting for (QQuickListModelWorkerAgent::sync() for example).
488     while (!isFinished()) {
489         // We can't simply wait here, because the worker thread will not terminate
490         // until the main thread processes the last data event it generates
491         QCoreApplication::processEvents();
492         yieldCurrentThread();
493     }
494
495     d->deleteLater();
496 }
497
498 QQuickWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
499 : id(-1), initialized(false), owner(0)
500 {
501 }
502
503 QQuickWorkerScriptEnginePrivate::WorkerScript::~WorkerScript()
504 {
505     qPersistentDispose(object);
506 }
507
508 int QQuickWorkerScriptEngine::registerWorkerScript(QQuickWorkerScript *owner)
509 {
510     typedef QQuickWorkerScriptEnginePrivate::WorkerScript WorkerScript;
511     WorkerScript *script = new WorkerScript;
512
513     script->id = d->m_nextId++;
514     script->owner = owner;
515
516     d->m_lock.lock();
517     d->workers.insert(script->id, script);
518     d->m_lock.unlock();
519
520     return script->id;
521 }
522
523 void QQuickWorkerScriptEngine::removeWorkerScript(int id)
524 {
525     QQuickWorkerScriptEnginePrivate::WorkerScript* script = d->workers.value(id);
526     if (script) {
527         script->owner = 0;
528         QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
529     }
530 }
531
532 void QQuickWorkerScriptEngine::executeUrl(int id, const QUrl &url)
533 {
534     QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
535 }
536
537 void QQuickWorkerScriptEngine::sendMessage(int id, const QByteArray &data)
538 {
539     QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
540 }
541
542 void QQuickWorkerScriptEngine::run()
543 {
544     d->m_lock.lock();
545
546     d->workerEngine = new QQuickWorkerScriptEnginePrivate::WorkerEngine(d);
547     d->workerEngine->init();
548
549     d->m_wait.wakeAll();
550
551     d->m_lock.unlock();
552
553     exec();
554
555     qDeleteAll(d->workers);
556     d->workers.clear();
557
558     delete d->workerEngine; d->workerEngine = 0;
559 }
560
561
562 /*!
563     \qmltype WorkerScript
564     \instantiates QQuickWorkerScript
565     \ingroup qtquick-threading
566     \inqmlmodule QtQuick 2
567     \brief Enables the use of threads in a Qt Quick application
568
569     Use WorkerScript to run operations in a new thread.
570     This is useful for running operations in the background so
571     that the main GUI thread is not blocked.
572
573     Messages can be passed between the new thread and the parent thread
574     using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler.
575
576     An example:
577
578     \snippet qml/workerscript/workerscript.qml 0
579
580     The above worker script specifies a JavaScript file, "script.js", that handles
581     the operations to be performed in the new thread. Here is \c script.js:
582
583     \quotefile qml/workerscript/script.js
584
585     When the user clicks anywhere within the rectangle, \c sendMessage() is
586     called, triggering the \tt WorkerScript.onMessage() handler in
587     \tt script.js. This in turn sends a reply message that is then received
588     by the \tt onMessage() handler of \tt myWorker.
589
590
591     \section3 Restrictions
592
593     Since the \c WorkerScript.onMessage() function is run in a separate thread, the
594     JavaScript file is evaluated in a context separate from the main QML engine. This means
595     that unlike an ordinary JavaScript file that is imported into QML, the \c script.js
596     in the above example cannot access the properties, methods or other attributes
597     of the QML item, nor can it access any context properties set on the QML object
598     through QQmlContext.
599
600     Additionally, there are restrictions on the types of values that can be passed to and
601     from the worker script. See the sendMessage() documentation for details.
602
603     \sa {declarative/threading/workerscript}{WorkerScript example},
604         {declarative/threading/threadedlistmodel}{Threaded ListModel example}
605 */
606 QQuickWorkerScript::QQuickWorkerScript(QObject *parent)
607 : QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true)
608 {
609 }
610
611 QQuickWorkerScript::~QQuickWorkerScript()
612 {
613     if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
614 }
615
616 /*!
617     \qmlproperty url WorkerScript::source
618
619     This holds the url of the JavaScript file that implements the
620     \tt WorkerScript.onMessage() handler for threaded operations.
621 */
622 QUrl QQuickWorkerScript::source() const
623 {
624     return m_source;
625 }
626
627 void QQuickWorkerScript::setSource(const QUrl &source)
628 {
629     if (m_source == source)
630         return;
631
632     m_source = source;
633
634     if (engine())
635         m_engine->executeUrl(m_scriptId, m_source);
636
637     emit sourceChanged();
638 }
639
640 /*!
641     \qmlmethod WorkerScript::sendMessage(jsobject message)
642
643     Sends the given \a message to a worker script handler in another
644     thread. The other worker script handler can receive this message
645     through the onMessage() handler.
646
647     The \c message object may only contain values of the following
648     types:
649
650     \list
651     \li boolean, number, string
652     \li JavaScript objects and arrays
653     \li ListModel objects (any other type of QObject* is not allowed)
654     \endlist
655
656     All objects and arrays are copied to the \c message. With the exception
657     of ListModel objects, any modifications by the other thread to an object
658     passed in \c message will not be reflected in the original object.
659 */
660 void QQuickWorkerScript::sendMessage(QQmlV8Function *args)
661 {
662     if (!engine()) {
663         qWarning("QQuickWorkerScript: Attempt to send message before WorkerScript establishment");
664         return;
665     }
666
667     v8::Handle<v8::Value> argument = v8::Undefined();
668     if (args->Length() != 0) 
669         argument = (*args)[0];
670
671     m_engine->sendMessage(m_scriptId, QV8Worker::serialize(argument, args->engine()));
672 }
673
674 void QQuickWorkerScript::classBegin()
675 {
676     m_componentComplete = false;
677 }
678
679 QQuickWorkerScriptEngine *QQuickWorkerScript::engine()
680 {
681     if (m_engine) return m_engine;
682     if (m_componentComplete) {
683         QQmlEngine *engine = qmlEngine(this);
684         if (!engine) {
685             qWarning("QQuickWorkerScript: engine() called without qmlEngine() set");
686             return 0;
687         }
688
689         m_engine = QQmlEnginePrivate::get(engine)->getWorkerScriptEngine();
690         m_scriptId = m_engine->registerWorkerScript(this);
691
692         if (m_source.isValid())
693             m_engine->executeUrl(m_scriptId, m_source);
694
695         return m_engine;
696     }
697     return 0;
698 }
699
700 void QQuickWorkerScript::componentComplete()
701 {
702     m_componentComplete = true;
703     engine(); // Get it started now.
704 }
705
706 /*!
707     \qmlsignal WorkerScript::onMessage(jsobject msg)
708
709     This handler is called when a message \a msg is received from a worker
710     script in another thread through a call to sendMessage().
711 */
712
713 bool QQuickWorkerScript::event(QEvent *event)
714 {
715     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
716         QQmlEngine *engine = qmlEngine(this);
717         if (engine) {
718             WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
719             QV8Engine *v8engine = QQmlEnginePrivate::get(engine)->v8engine();
720             v8::HandleScope handle_scope;
721             v8::Context::Scope scope(v8engine->context());
722             v8::Handle<v8::Value> value = QV8Worker::deserialize(workerEvent->data(), v8engine);
723             emit message(QQmlV8Handle::fromHandle(value));
724         }
725         return true;
726     } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
727         WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event);
728         QQmlEnginePrivate::warning(qmlEngine(this), workerEvent->error());
729         return true;
730     } else {
731         return QObject::event(event);
732     }
733 }
734
735 QT_END_NAMESPACE
736
737 #include <qquickworkerscript.moc>
738