Fix crashes caused by handle management in worker threads
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeworkerscript.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativeworkerscript_p.h"
43 #include "private/qdeclarativelistmodel_p.h"
44 #include "private/qdeclarativelistmodelworkeragent_p.h"
45 #include "private/qdeclarativeengine_p.h"
46 #include "private/qdeclarativeexpression_p.h"
47
48 #include <QtCore/qcoreevent.h>
49 #include <QtCore/qcoreapplication.h>
50 #include <QtCore/qdebug.h>
51 #include <QtDeclarative/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 <QtDeclarative/qdeclarativeinfo.h>
58 #include "qdeclarativenetworkaccessmanagerfactory.h"
59
60 #include <private/qv8engine_p.h>
61 #include <private/qv8worker_p.h>
62 #include <private/qv8gccallback_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 QDeclarativeError &error);
116
117     QDeclarativeError error() const;
118
119 private:
120     QDeclarativeError m_error;
121 };
122
123 class QDeclarativeWorkerScriptEnginePrivate : public QObject
124 {
125     Q_OBJECT
126 public:
127     enum WorkerEventTypes {
128         WorkerDestroyEvent = QEvent::User + 100
129     };
130
131     QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng);
132
133     class WorkerEngine : public QV8Engine
134     {
135     public:
136         WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent);
137         ~WorkerEngine();
138
139         void init();
140         virtual QNetworkAccessManager *networkAccessManager();
141
142         QDeclarativeWorkerScriptEnginePrivate *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 QDeclarativeWorkerScriptEnginePrivate *get(QV8Engine *e) {
154         return static_cast<WorkerEngine *>(e)->p;
155     }
156
157     QDeclarativeEngine *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         QDeclarativeWorkerScript *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 QDeclarativeError &error);
190 };
191
192 QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent) 
193 : QV8Engine(0), p(parent), accessManager(0)
194 {
195 }
196
197 QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine() 
198
199     qPersistentDispose(createsend);
200     qPersistentDispose(onmessage);
201     delete accessManager; 
202 }
203
204 void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::init()
205 {
206     initDeclarativeGlobalObject();
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(QDeclarativeWorkerScriptEnginePrivate::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> QDeclarativeWorkerScriptEnginePrivate::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 QDeclarativeWorkerScriptEnginePrivate::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 *QDeclarativeWorkerScriptEnginePrivate::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 QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine)
274 : workerEngine(0), qmlengine(engine), m_nextId(0)
275 {
276 }
277
278 v8::Handle<v8::Value> QDeclarativeWorkerScriptEnginePrivate::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(&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> QDeclarativeWorkerScriptEnginePrivate::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 QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event)
319 {
320     // XXX must handle remove request
321     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
322         WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
323         processMessage(workerEvent->workerId(), workerEvent->data());
324         return true;
325     } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
326         WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
327         processLoad(workerEvent->workerId(), workerEvent->url());
328         return true;
329     } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) {
330         emit stopThread();
331         return true;
332     } else {
333         return QObject::event(event);
334     }
335 }
336
337 void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &data)
338 {
339     WorkerScript *script = workers.value(id);
340     if (!script)
341         return;
342
343     v8::HandleScope handle_scope;
344     v8::Context::Scope scope(workerEngine->context());
345
346     v8::Handle<v8::Value> value = QV8Worker::deserialize(data, workerEngine);
347
348     v8::TryCatch tc;
349     workerEngine->callOnMessage(script->object, value);
350
351     if (tc.HasCaught()) {
352         QDeclarativeError error;
353         QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
354         reportScriptException(script, error);
355     }
356 }
357
358 void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
359 {
360     if (url.isRelative())
361         return;
362
363     QString fileName = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
364
365     QFile f(fileName);
366     if (f.open(QIODevice::ReadOnly)) {
367         QByteArray data = f.readAll();
368         QString sourceCode = QString::fromUtf8(data);
369         QDeclarativeScript::Parser::extractPragmas(sourceCode);
370
371         v8::HandleScope handle_scope;
372         v8::Context::Scope scope(workerEngine->context());
373
374         WorkerScript *script = workers.value(id);
375         if (!script)
376             return;
377         script->source = url;
378         v8::Handle<v8::Object> activation = getWorker(script);
379         if (activation.IsEmpty())
380             return;
381
382         // XXX ???
383         // workerEngine->baseUrl = url;
384
385         v8::TryCatch tc;
386         v8::Local<v8::Script> program = workerEngine->qmlModeCompile(sourceCode, url.toString());
387
388         if (!tc.HasCaught()) 
389             program->Run(activation);
390         
391         if (tc.HasCaught()) {
392             QDeclarativeError error;
393             QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
394             reportScriptException(script, error);
395         }
396     } else {
397         qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
398     }
399 }
400
401 void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script, 
402                                                                   const QDeclarativeError &error)
403 {
404     QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(workerEngine);
405
406     QMutexLocker(&p->m_lock);
407     if (script->owner)
408         QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
409 }
410
411 WorkerDataEvent::WorkerDataEvent(int workerId, const QByteArray &data)
412 : QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
413 {
414 }
415
416 WorkerDataEvent::~WorkerDataEvent()
417 {
418 }
419
420 int WorkerDataEvent::workerId() const
421 {
422     return m_id;
423 }
424
425 QByteArray WorkerDataEvent::data() const
426 {
427     return m_data;
428 }
429
430 WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
431 : QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url)
432 {
433 }
434
435 int WorkerLoadEvent::workerId() const
436 {
437     return m_id;
438 }
439
440 QUrl WorkerLoadEvent::url() const
441 {
442     return m_url;
443 }
444
445 WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
446 : QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
447 {
448 }
449
450 int WorkerRemoveEvent::workerId() const
451 {
452     return m_id;
453 }
454
455 WorkerErrorEvent::WorkerErrorEvent(const QDeclarativeError &error)
456 : QEvent((QEvent::Type)WorkerError), m_error(error)
457 {
458 }
459
460 QDeclarativeError WorkerErrorEvent::error() const
461 {
462     return m_error;
463 }
464
465 QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent)
466 : QThread(parent), d(new QDeclarativeWorkerScriptEnginePrivate(parent))
467 {
468     d->m_lock.lock();
469     connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection);
470     start(QThread::IdlePriority);
471     d->m_wait.wait(&d->m_lock);
472     d->moveToThread(this);
473     d->m_lock.unlock();
474 }
475
476 QDeclarativeWorkerScriptEngine::~QDeclarativeWorkerScriptEngine()
477 {
478     d->m_lock.lock();
479     QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QDeclarativeWorkerScriptEnginePrivate::WorkerDestroyEvent));
480     d->m_lock.unlock();
481
482     wait();
483     d->deleteLater();
484 }
485
486 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
487 : id(-1), initialized(false), owner(0)
488 {
489 }
490
491 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::~WorkerScript()
492 {
493     qPersistentDispose(object);
494 }
495
496 int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner)
497 {
498     typedef QDeclarativeWorkerScriptEnginePrivate::WorkerScript WorkerScript;
499     WorkerScript *script = new WorkerScript;
500
501     script->id = d->m_nextId++;
502     script->owner = owner;
503
504     d->m_lock.lock();
505     d->workers.insert(script->id, script);
506     d->m_lock.unlock();
507
508     return script->id;
509 }
510
511 void QDeclarativeWorkerScriptEngine::removeWorkerScript(int id)
512 {
513     QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
514 }
515
516 void QDeclarativeWorkerScriptEngine::executeUrl(int id, const QUrl &url)
517 {
518     QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
519 }
520
521 void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QByteArray &data)
522 {
523     QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
524 }
525
526 void QDeclarativeWorkerScriptEngine::run()
527 {
528     d->m_lock.lock();
529
530     v8::Isolate *isolate = v8::Isolate::New(); 
531     isolate->Enter();
532
533     d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::WorkerEngine(d);
534     d->workerEngine->init();
535
536     d->m_wait.wakeAll();
537
538     d->m_lock.unlock();
539
540     exec();
541
542     qDeleteAll(d->workers);
543     d->workers.clear();
544
545     delete d->workerEngine; d->workerEngine = 0;
546     QV8GCCallback::releaseWorkerThreadGcPrologueCallbackData();
547     isolate->Exit();
548     isolate->Dispose();
549 }
550
551
552 /*!
553     \qmlclass WorkerScript QDeclarativeWorkerScript
554     \ingroup qml-utility-elements
555     \brief The WorkerScript element enables the use of threads in QML.
556
557     Use WorkerScript to run operations in a new thread.
558     This is useful for running operations in the background so
559     that the main GUI thread is not blocked.
560
561     Messages can be passed between the new thread and the parent thread
562     using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler.
563
564     An example:
565
566     \snippet doc/src/snippets/declarative/workerscript.qml 0
567
568     The above worker script specifies a JavaScript file, "script.js", that handles
569     the operations to be performed in the new thread. Here is \c script.js:
570
571     \quotefile doc/src/snippets/declarative/script.js
572
573     When the user clicks anywhere within the rectangle, \c sendMessage() is
574     called, triggering the \tt WorkerScript.onMessage() handler in
575     \tt script.js. This in turn sends a reply message that is then received
576     by the \tt onMessage() handler of \tt myWorker.
577
578
579     \section3 Restrictions
580
581     Since the \c WorkerScript.onMessage() function is run in a separate thread, the
582     JavaScript file is evaluated in a context separate from the main QML engine. This means
583     that unlike an ordinary JavaScript file that is imported into QML, the \c script.js
584     in the above example cannot access the properties, methods or other attributes
585     of the QML item, nor can it access any context properties set on the QML object
586     through QDeclarativeContext.
587
588     Additionally, there are restrictions on the types of values that can be passed to and
589     from the worker script. See the sendMessage() documentation for details.
590
591     \sa {declarative/threading/workerscript}{WorkerScript example},
592         {declarative/threading/threadedlistmodel}{Threaded ListModel example}
593 */
594 QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent)
595 : QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true)
596 {
597 }
598
599 QDeclarativeWorkerScript::~QDeclarativeWorkerScript()
600 {
601     if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
602 }
603
604 /*!
605     \qmlproperty url WorkerScript::source
606
607     This holds the url of the JavaScript file that implements the
608     \tt WorkerScript.onMessage() handler for threaded operations.
609 */
610 QUrl QDeclarativeWorkerScript::source() const
611 {
612     return m_source;
613 }
614
615 void QDeclarativeWorkerScript::setSource(const QUrl &source)
616 {
617     if (m_source == source)
618         return;
619
620     m_source = source;
621
622     if (engine())
623         m_engine->executeUrl(m_scriptId, m_source);
624
625     emit sourceChanged();
626 }
627
628 /*!
629     \qmlmethod WorkerScript::sendMessage(jsobject message)
630
631     Sends the given \a message to a worker script handler in another
632     thread. The other worker script handler can receive this message
633     through the onMessage() handler.
634
635     The \c message object may only contain values of the following
636     types:
637
638     \list
639     \o boolean, number, string
640     \o JavaScript objects and arrays
641     \o ListModel objects (any other type of QObject* is not allowed)
642     \endlist
643
644     All objects and arrays are copied to the \c message. With the exception
645     of ListModel objects, any modifications by the other thread to an object
646     passed in \c message will not be reflected in the original object.
647 */
648 void QDeclarativeWorkerScript::sendMessage(QDeclarativeV8Function *args)
649 {
650     if (!engine()) {
651         qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment");
652         return;
653     }
654
655     v8::Handle<v8::Value> argument = v8::Undefined();
656     if (args->Length() != 0) 
657         argument = (*args)[0];
658
659     m_engine->sendMessage(m_scriptId, QV8Worker::serialize(argument, args->engine()));
660 }
661
662 void QDeclarativeWorkerScript::classBegin()
663 {
664     m_componentComplete = false;
665 }
666
667 QDeclarativeWorkerScriptEngine *QDeclarativeWorkerScript::engine()
668 {
669     if (m_engine) return m_engine;
670     if (m_componentComplete) {
671         QDeclarativeEngine *engine = qmlEngine(this);
672         if (!engine) {
673             qWarning("QDeclarativeWorkerScript: engine() called without qmlEngine() set");
674             return 0;
675         }
676
677         m_engine = QDeclarativeEnginePrivate::get(engine)->getWorkerScriptEngine();
678         m_scriptId = m_engine->registerWorkerScript(this);
679
680         if (m_source.isValid())
681             m_engine->executeUrl(m_scriptId, m_source);
682
683         return m_engine;
684     }
685     return 0;
686 }
687
688 void QDeclarativeWorkerScript::componentComplete()
689 {
690     m_componentComplete = true;
691     engine(); // Get it started now.
692 }
693
694 /*!
695     \qmlsignal WorkerScript::onMessage(jsobject msg)
696
697     This handler is called when a message \a msg is received from a worker
698     script in another thread through a call to sendMessage().
699 */
700
701 bool QDeclarativeWorkerScript::event(QEvent *event)
702 {
703     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
704         QDeclarativeEngine *engine = qmlEngine(this);
705         if (engine) {
706             WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
707             QV8Engine *v8engine = QDeclarativeEnginePrivate::get(engine)->v8engine();
708             v8::HandleScope handle_scope;
709             v8::Context::Scope scope(v8engine->context());
710             v8::Handle<v8::Value> value = QV8Worker::deserialize(workerEvent->data(), v8engine);
711             emit message(QDeclarativeV8Handle::fromHandle(value));
712         }
713         return true;
714     } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
715         WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event);
716         QDeclarativeEnginePrivate::warning(qmlEngine(this), workerEvent->error());
717         return true;
718     } else {
719         return QObject::event(event);
720     }
721 }
722
723 QT_END_NAMESPACE
724
725 #include <qdeclarativeworkerscript.moc>
726