Dispose of WorkerScripts in correct Isolate
[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 <QtScript/qscriptengine.h>
52 #include <QtCore/qmutex.h>
53 #include <QtCore/qwaitcondition.h>
54 #include <QtScript/qscriptvalueiterator.h>
55 #include <QtCore/qfile.h>
56 #include <QtCore/qdatetime.h>
57 #include <QtNetwork/qnetworkaccessmanager.h>
58 #include <QtDeclarative/qdeclarativeinfo.h>
59 #include "qdeclarativenetworkaccessmanagerfactory.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 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 : p(parent), accessManager(0) 
194 {
195 }
196
197 QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine() 
198
199     createsend.Dispose(); createsend.Clear();
200     onmessage.Dispose(); onmessage.Clear();
201     delete accessManager; 
202 }
203
204 void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::init()
205 {
206     QV8Engine::init(0);
207
208 #define CALL_ONMESSAGE_SCRIPT \
209     "(function(object, message) { "\
210         "var isfunction = false; "\
211         "try { "\
212             "isfunction = object.WorkerScript.onMessage instanceof Function; "\
213         "} catch (e) {}" \
214         "if (isfunction) "\
215             "object.WorkerScript.onMessage(message); "\
216     "})"
217
218 #define SEND_MESSAGE_CREATE_SCRIPT \
219     "(function(method, engine) { "\
220         "return (function(id) { "\
221             "return (function(message) { "\
222                 "if (arguments.length) method(engine, id, message); "\
223             "}); "\
224         "}); "\
225     "})"
226
227     v8::HandleScope handle_scope;
228     v8::Context::Scope scope(context());
229
230     {
231     v8::Local<v8::Script> onmessagescript = v8::Script::New(v8::String::New(CALL_ONMESSAGE_SCRIPT));
232     onmessage = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(onmessagescript->Run()));
233     }
234     {
235     v8::Local<v8::Script> createsendscript = v8::Script::New(v8::String::New(SEND_MESSAGE_CREATE_SCRIPT));
236     v8::Local<v8::Function> createsendconstructor = v8::Local<v8::Function>::Cast(createsendscript->Run());
237
238     v8::Handle<v8::Value> args[] = { 
239         V8FUNCTION(QDeclarativeWorkerScriptEnginePrivate::sendMessage, this)
240     };
241     v8::Local<v8::Value> createsendvalue = createsendconstructor->Call(global(), 1, args);
242     
243     createsend = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(createsendvalue));
244     }
245 }
246
247 // Requires handle and context scope
248 v8::Local<v8::Function> QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::sendFunction(int id)
249 {
250     v8::Handle<v8::Value> args[] = { v8::Integer::New(id) };
251     return v8::Local<v8::Function>::Cast(createsend->Call(global(), 1, args));
252 }
253
254 // Requires handle and context scope
255 void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::callOnMessage(v8::Handle<v8::Object> object, 
256                                                                         v8::Handle<v8::Value> arg)
257 {
258     v8::Handle<v8::Value> args[] = { object, arg };
259     onmessage->Call(global(), 2, args);
260 }
261
262 QNetworkAccessManager *QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::networkAccessManager() 
263 {
264     if (!accessManager) {
265         if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
266             accessManager = p->qmlengine->networkAccessManagerFactory()->create(p);
267         } else {
268             accessManager = new QNetworkAccessManager(p);
269         }
270     }
271     return accessManager;
272 }
273
274 QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine)
275 : workerEngine(0), qmlengine(engine), m_nextId(0)
276 {
277 }
278
279 v8::Handle<v8::Value> QDeclarativeWorkerScriptEnginePrivate::sendMessage(const v8::Arguments &args)
280 {
281     WorkerEngine *engine = (WorkerEngine*)V8ENGINE();
282
283     int id = args[1]->Int32Value();
284
285     QByteArray data = QV8Worker::serialize(args[2], engine);
286
287     QMutexLocker(&engine->p->m_lock);
288     WorkerScript *script = engine->p->workers.value(id);
289     if (!script)
290         return v8::Undefined();
291
292     if (script->owner)
293         QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data));
294
295     return v8::Undefined();
296 }
297
298 // Requires handle scope and context scope
299 v8::Handle<v8::Object> QDeclarativeWorkerScriptEnginePrivate::getWorker(WorkerScript *script)
300 {
301     if (!script->initialized) {
302         script->initialized = true;
303
304         script->object = v8::Persistent<v8::Object>::New(workerEngine->contextWrapper()->urlScope(script->source));
305
306         workerEngine->contextWrapper()->setReadOnly(script->object, false);
307
308         v8::Local<v8::Object> api = v8::Object::New();
309         api->Set(v8::String::New("sendMessage"), workerEngine->sendFunction(script->id));
310
311         script->object->Set(v8::String::New("WorkerScript"), api);
312
313         workerEngine->contextWrapper()->setReadOnly(script->object, true);
314     }
315
316     return script->object;
317 }
318
319 bool QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event)
320 {
321     // XXX must handle remove request
322     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
323         WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
324         processMessage(workerEvent->workerId(), workerEvent->data());
325         return true;
326     } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
327         WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
328         processLoad(workerEvent->workerId(), workerEvent->url());
329         return true;
330     } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) {
331         emit stopThread();
332         return true;
333     } else {
334         return QObject::event(event);
335     }
336 }
337
338 void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &data)
339 {
340     WorkerScript *script = workers.value(id);
341     if (!script)
342         return;
343
344     v8::HandleScope handle_scope;
345     v8::Context::Scope scope(workerEngine->context());
346
347     v8::Handle<v8::Value> value = QV8Worker::deserialize(data, workerEngine);
348
349     v8::TryCatch tc;
350     workerEngine->callOnMessage(script->object, value);
351
352     if (tc.HasCaught()) {
353         QDeclarativeError error;
354         QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
355         reportScriptException(script, error);
356     }
357 }
358
359 void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
360 {
361     if (url.isRelative())
362         return;
363
364     QString fileName = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
365
366     QFile f(fileName);
367     if (f.open(QIODevice::ReadOnly)) {
368         QByteArray data = f.readAll();
369         QString sourceCode = QString::fromUtf8(data);
370         QDeclarativeScriptParser::extractPragmas(sourceCode);
371
372         v8::HandleScope handle_scope;
373         v8::Context::Scope scope(workerEngine->context());
374
375         WorkerScript *script = workers.value(id);
376         if (!script)
377             return;
378         script->source = url;
379         v8::Handle<v8::Object> activation = getWorker(script);
380         if (activation.IsEmpty())
381             return;
382
383         // XXX ???
384         // workerEngine->baseUrl = url;
385
386         v8::TryCatch tc;
387         v8::Local<v8::Script> program = workerEngine->qmlModeCompile(sourceCode, url.toString());
388
389         if (!tc.HasCaught()) 
390             program->Run(activation);
391         
392         if (tc.HasCaught()) {
393             QDeclarativeError error;
394             QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
395             reportScriptException(script, error);
396         }
397     } else {
398         qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
399     }
400 }
401
402 void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script, 
403                                                                   const QDeclarativeError &error)
404 {
405     QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(workerEngine);
406
407     QMutexLocker(&p->m_lock);
408     if (script->owner)
409         QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
410 }
411
412 WorkerDataEvent::WorkerDataEvent(int workerId, const QByteArray &data)
413 : QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
414 {
415 }
416
417 WorkerDataEvent::~WorkerDataEvent()
418 {
419 }
420
421 int WorkerDataEvent::workerId() const
422 {
423     return m_id;
424 }
425
426 QByteArray WorkerDataEvent::data() const
427 {
428     return m_data;
429 }
430
431 WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
432 : QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url)
433 {
434 }
435
436 int WorkerLoadEvent::workerId() const
437 {
438     return m_id;
439 }
440
441 QUrl WorkerLoadEvent::url() const
442 {
443     return m_url;
444 }
445
446 WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
447 : QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
448 {
449 }
450
451 int WorkerRemoveEvent::workerId() const
452 {
453     return m_id;
454 }
455
456 WorkerErrorEvent::WorkerErrorEvent(const QDeclarativeError &error)
457 : QEvent((QEvent::Type)WorkerError), m_error(error)
458 {
459 }
460
461 QDeclarativeError WorkerErrorEvent::error() const
462 {
463     return m_error;
464 }
465
466 QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent)
467 : QThread(parent), d(new QDeclarativeWorkerScriptEnginePrivate(parent))
468 {
469     d->m_lock.lock();
470     connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection);
471     start(QThread::IdlePriority);
472     d->m_wait.wait(&d->m_lock);
473     d->moveToThread(this);
474     d->m_lock.unlock();
475 }
476
477 QDeclarativeWorkerScriptEngine::~QDeclarativeWorkerScriptEngine()
478 {
479     d->m_lock.lock();
480     QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QDeclarativeWorkerScriptEnginePrivate::WorkerDestroyEvent));
481     d->m_lock.unlock();
482
483     wait();
484     d->deleteLater();
485 }
486
487 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
488 : id(-1), initialized(false), owner(0)
489 {
490 }
491
492 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::~WorkerScript()
493 {
494     object.Dispose(); object.Clear();
495 }
496
497 int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner)
498 {
499     typedef QDeclarativeWorkerScriptEnginePrivate::WorkerScript WorkerScript;
500     WorkerScript *script = new WorkerScript;
501
502     script->id = d->m_nextId++;
503     script->owner = owner;
504
505     d->m_lock.lock();
506     d->workers.insert(script->id, script);
507     d->m_lock.unlock();
508
509     return script->id;
510 }
511
512 void QDeclarativeWorkerScriptEngine::removeWorkerScript(int id)
513 {
514     QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
515 }
516
517 void QDeclarativeWorkerScriptEngine::executeUrl(int id, const QUrl &url)
518 {
519     QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
520 }
521
522 void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QByteArray &data)
523 {
524     QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
525 }
526
527 void QDeclarativeWorkerScriptEngine::run()
528 {
529     d->m_lock.lock();
530
531     v8::Isolate *isolate = v8::Isolate::New(); 
532     isolate->Enter();
533
534     d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::WorkerEngine(d);
535     d->workerEngine->init();
536
537     d->m_wait.wakeAll();
538
539     d->m_lock.unlock();
540
541     exec();
542
543     qDeleteAll(d->workers);
544     d->workers.clear();
545
546     delete d->workerEngine; d->workerEngine = 0;
547
548     isolate->Exit();
549     isolate->Dispose();
550 }
551
552
553 /*!
554     \qmlclass WorkerScript QDeclarativeWorkerScript
555     \ingroup qml-utility-elements
556     \brief The WorkerScript element enables the use of threads in QML.
557
558     Use WorkerScript to run operations in a new thread.
559     This is useful for running operations in the background so
560     that the main GUI thread is not blocked.
561
562     Messages can be passed between the new thread and the parent thread
563     using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler.
564
565     An example:
566
567     \snippet doc/src/snippets/declarative/workerscript.qml 0
568
569     The above worker script specifies a JavaScript file, "script.js", that handles
570     the operations to be performed in the new thread. Here is \c script.js:
571
572     \quotefile doc/src/snippets/declarative/script.js
573
574     When the user clicks anywhere within the rectangle, \c sendMessage() is
575     called, triggering the \tt WorkerScript.onMessage() handler in
576     \tt script.js. This in turn sends a reply message that is then received
577     by the \tt onMessage() handler of \tt myWorker.
578
579
580     \section3 Restrictions
581
582     Since the \c WorkerScript.onMessage() function is run in a separate thread, the
583     JavaScript file is evaluated in a context separate from the main QML engine. This means
584     that unlike an ordinary JavaScript file that is imported into QML, the \c script.js
585     in the above example cannot access the properties, methods or other attributes
586     of the QML item, nor can it access any context properties set on the QML object
587     through QDeclarativeContext.
588
589     Additionally, there are restrictions on the types of values that can be passed to and
590     from the worker script. See the sendMessage() documentation for details.
591
592     \sa {declarative/threading/workerscript}{WorkerScript example},
593         {declarative/threading/threadedlistmodel}{Threaded ListModel example}
594 */
595 QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent)
596 : QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true)
597 {
598 }
599
600 QDeclarativeWorkerScript::~QDeclarativeWorkerScript()
601 {
602     if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
603 }
604
605 /*!
606     \qmlproperty url WorkerScript::source
607
608     This holds the url of the JavaScript file that implements the
609     \tt WorkerScript.onMessage() handler for threaded operations.
610 */
611 QUrl QDeclarativeWorkerScript::source() const
612 {
613     return m_source;
614 }
615
616 void QDeclarativeWorkerScript::setSource(const QUrl &source)
617 {
618     if (m_source == source)
619         return;
620
621     m_source = source;
622
623     if (engine())
624         m_engine->executeUrl(m_scriptId, m_source);
625
626     emit sourceChanged();
627 }
628
629 /*!
630     \qmlmethod WorkerScript::sendMessage(jsobject message)
631
632     Sends the given \a message to a worker script handler in another
633     thread. The other worker script handler can receive this message
634     through the onMessage() handler.
635
636     The \c message object may only contain values of the following
637     types:
638
639     \list
640     \o boolean, number, string
641     \o JavaScript objects and arrays
642     \o ListModel objects (any other type of QObject* is not allowed)
643     \endlist
644
645     All objects and arrays are copied to the \c message. With the exception
646     of ListModel objects, any modifications by the other thread to an object
647     passed in \c message will not be reflected in the original object.
648 */
649 void QDeclarativeWorkerScript::sendMessage(QDeclarativeV8Function *args)
650 {
651     if (!engine()) {
652         qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment");
653         return;
654     }
655
656     v8::Handle<v8::Value> argument = v8::Undefined();
657     if (args->Length() != 0) 
658         argument = (*args)[0];
659
660     m_engine->sendMessage(m_scriptId, QV8Worker::serialize(argument, args->engine()));
661 }
662
663 void QDeclarativeWorkerScript::classBegin()
664 {
665     m_componentComplete = false;
666 }
667
668 QDeclarativeWorkerScriptEngine *QDeclarativeWorkerScript::engine()
669 {
670     if (m_engine) return m_engine;
671     if (m_componentComplete) {
672         QDeclarativeEngine *engine = qmlEngine(this);
673         if (!engine) {
674             qWarning("QDeclarativeWorkerScript: engine() called without qmlEngine() set");
675             return 0;
676         }
677
678         m_engine = QDeclarativeEnginePrivate::get(engine)->getWorkerScriptEngine();
679         m_scriptId = m_engine->registerWorkerScript(this);
680
681         if (m_source.isValid())
682             m_engine->executeUrl(m_scriptId, m_source);
683
684         return m_engine;
685     }
686     return 0;
687 }
688
689 void QDeclarativeWorkerScript::componentComplete()
690 {
691     m_componentComplete = true;
692     engine(); // Get it started now.
693 }
694
695 /*!
696     \qmlsignal WorkerScript::onMessage(jsobject msg)
697
698     This handler is called when a message \a msg is received from a worker
699     script in another thread through a call to sendMessage().
700 */
701
702 bool QDeclarativeWorkerScript::event(QEvent *event)
703 {
704     if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
705         QDeclarativeEngine *engine = qmlEngine(this);
706         if (engine) {
707             WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
708             QV8Engine *v8engine = &QDeclarativeEnginePrivate::get(engine)->v8engine;
709             v8::HandleScope handle_scope;
710             v8::Context::Scope scope(v8engine->context());
711             v8::Handle<v8::Value> value = QV8Worker::deserialize(workerEvent->data(), v8engine);
712             emit message(QDeclarativeV8Handle::fromHandle(value));
713         }
714         return true;
715     } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
716         WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event);
717         QDeclarativeEnginePrivate::warning(qmlEngine(this), workerEvent->error());
718         return true;
719     } else {
720         return QObject::event(event);
721     }
722 }
723
724 QT_END_NAMESPACE
725
726 #include <qdeclarativeworkerscript.moc>
727