Detect and abort if an object is deleted during signal handling
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlengine.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 "qqmlengine_p.h"
43 #include "qqmlengine.h"
44 #include "qqmlcomponentattached_p.h"
45
46 #include "qqmlcontext_p.h"
47 #include "qqmlcompiler_p.h"
48 #include "qqml.h"
49 #include "qqmlcontext.h"
50 #include "qqmlexpression.h"
51 #include "qqmlcomponent.h"
52 #include "qqmlvme_p.h"
53 #include <private/qqmlenginedebugservice_p.h>
54 #include "qqmlstringconverters_p.h"
55 #include "qqmlxmlhttprequest_p.h"
56 #include "qqmlscriptstring.h"
57 #include "qqmlglobal_p.h"
58 #include "qquicklistmodel_p.h"
59 #include "qquickworkerscript_p.h"
60 #include "qqmlcomponent_p.h"
61 #include "qqmlnetworkaccessmanagerfactory.h"
62 #include "qqmldirparser_p.h"
63 #include "qqmlextensioninterface.h"
64 #include "qqmllist_p.h"
65 #include "qqmltypenamecache_p.h"
66 #include "qqmlnotifier_p.h"
67 #include <private/qqmlprofilerservice_p.h>
68 #include <private/qv8debugservice_p.h>
69 #include <private/qdebugmessageservice_p.h>
70 #include "qqmlincubator.h"
71 #include <private/qv8profilerservice_p.h>
72 #include <private/qqmlboundsignal_p.h>
73
74 #include <QtCore/qstandardpaths.h>
75 #include <QtCore/qsettings.h>
76
77 #include <QtCore/qmetaobject.h>
78 #include <QNetworkAccessManager>
79 #include <QDebug>
80 #include <QtCore/qcoreapplication.h>
81 #include <QtCore/qdir.h>
82 #include <QtCore/qmutex.h>
83 #include <QtCore/qthread.h>
84 #include <private/qthread_p.h>
85 #include <QtNetwork/qnetworkconfigmanager.h>
86
87 #include <private/qobject_p.h>
88 #include <private/qmetaobject_p.h>
89
90 #include <private/qqmllocale_p.h>
91
92 #ifdef Q_OS_WIN // for %APPDATA%
93 #include <qt_windows.h>
94 #include <qlibrary.h>
95 #include <windows.h>
96
97 #define CSIDL_APPDATA           0x001a  // <username>\Application Data
98 #endif
99
100 Q_DECLARE_METATYPE(QQmlProperty)
101
102 QT_BEGIN_NAMESPACE
103
104 void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor)
105 {
106     QQmlEnginePrivate::registerBaseTypes(uri, versionMajor, versionMinor);
107     QQmlValueTypeFactory::registerBaseTypes(uri, versionMajor, versionMinor);
108 }
109
110 /*!
111   \qmlclass QtObject QObject
112   \ingroup qml-utility-elements
113   \since 4.7
114   \brief The QtObject element is the most basic element in QML.
115
116   The QtObject element is a non-visual element which contains only the
117   objectName property.
118
119   It can be useful to create a QtObject if you need an extremely
120   lightweight element to enclose a set of custom properties:
121
122   \snippet doc/snippets/qml/qtobject.qml 0
123
124   It can also be useful for C++ integration, as it is just a plain
125   QObject. See the QObject documentation for further details.
126 */
127 /*!
128   \qmlproperty string QtObject::objectName
129   This property holds the QObject::objectName for this specific object instance.
130
131   This allows a C++ application to locate an item within a QML component
132   using the QObject::findChild() method. For example, the following C++
133   application locates the child \l Rectangle item and dynamically changes its
134   \c color value:
135
136     \qml
137     // MyRect.qml
138
139     import QtQuick 2.0
140
141     Item {
142         width: 200; height: 200
143
144         Rectangle {
145             anchors.fill: parent
146             color: "red"
147             objectName: "myRect"
148         }
149     }
150     \endqml
151
152     \code
153     // main.cpp
154
155     QQuickView view;
156     view.setSource(QUrl::fromLocalFile("MyRect.qml"));
157     view.show();
158
159     QQuickItem *item = view.rootObject()->findChild<QQuickItem*>("myRect");
160     if (item)
161         item->setProperty("color", QColor(Qt::yellow));
162     \endcode
163 */
164
165 bool QQmlEnginePrivate::qml_debugging_enabled = false;
166
167 void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int versionMinor)
168 {
169     qmlRegisterType<QQmlComponent>(uri,versionMajor,versionMinor,"Component");
170     qmlRegisterType<QObject>(uri,versionMajor,versionMinor,"QtObject");
171     qmlRegisterType<QQuickListElement>(uri, versionMajor, versionMinor,"ListElement");
172     qmlRegisterCustomType<QQuickListModel>(uri, versionMajor, versionMinor,"ListModel", new QQuickListModelParser);
173     qmlRegisterType<QQuickWorkerScript>(uri,versionMajor,versionMinor,"WorkerScript");
174 }
175
176 void QQmlEnginePrivate::defineModule()
177 {
178     registerBaseTypes("QtQuick", 2, 0);
179     qmlRegisterUncreatableType<QQmlLocale>("QtQuick",2,0,"Locale",QQmlEngine::tr("Locale cannot be instantiated.  Use Qt.locale()"));
180 }
181
182
183 /*!
184     \class QQmlImageProviderBase
185     \brief The QQmlImageProviderBase class is used to register image providers in the QML engine.
186     \mainclass
187
188     Image providers must be registered with the QML engine.  The only information the QML
189     engine knows about image providers is the type of image data they provide.  To use an
190     image provider to acquire image data, you must cast the QQmlImageProviderBase pointer
191     to a QQuickImageProvider pointer.
192
193     \sa QQuickImageProvider, QQuickTextureFactory
194 */
195
196 /*!
197     \enum QQmlImageProviderBase::ImageType
198
199     Defines the type of image supported by this image provider.
200
201     \value Image The Image Provider provides QImage images.
202         The QQuickImageProvider::requestImage() method will be called for all image requests.
203     \value Pixmap The Image Provider provides QPixmap images.
204         The QQuickImageProvider::requestPixmap() method will be called for all image requests.
205     \value Texture The Image Provider provides QSGTextureProvider based images.
206         The QQuickImageProvider::requestTexture() method will be called for all image requests. \omitvalue
207 */
208
209 /*!
210     \enum QQmlImageProviderBase::Flag
211
212     Defines specific requirements or features of this image provider.
213
214     \value ForceAsynchronousImageLoading Ensures that image requests to the provider are
215         run in a separate thread, which allows the provider to spend as much time as needed
216         on producing the image without blocking the main thread.
217 */
218
219 /*! \internal */
220 QQmlImageProviderBase::QQmlImageProviderBase()
221 {
222 }
223
224 /*! \internal */
225 QQmlImageProviderBase::~QQmlImageProviderBase()
226 {
227 }
228
229
230 /*!
231 \qmlclass Qt QQmlEnginePrivate
232   \ingroup qml-utility-elements
233 \brief The QML global Qt object provides useful enums and functions from Qt.
234
235 \keyword QmlGlobalQtObject
236
237 \brief The \c Qt object provides useful enums and functions from Qt, for use in all QML files.
238
239 The \c Qt object is a global object with utility functions, properties and enums.
240
241 It is not instantiable; to use it, call the members of the global \c Qt object directly.
242 For example:
243
244 \qml
245 import QtQuick 2.0
246
247 Text {
248     color: Qt.rgba(1, 0, 0, 1)
249     text: Qt.md5("hello, world")
250 }
251 \endqml
252
253
254 \section1 Enums
255
256 The Qt object contains the enums available in the \l {Qt Namespace}. For example, you can access
257 the \l Qt::LeftButton and \l Qt::RightButton enum values as \c Qt.LeftButton and \c Qt.RightButton.
258
259
260 \section1 Types
261 The Qt object also contains helper functions for creating objects of specific
262 data types. This is primarily useful when setting the properties of an item
263 when the property has one of the following types:
264
265 \list
266 \li \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()}
267 \li \c rect - use \l{Qt::rect()}{Qt.rect()}
268 \li \c point - use \l{Qt::point()}{Qt.point()}
269 \li \c size - use \l{Qt::size()}{Qt.size()}
270 \li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
271 \endlist
272
273 There are also string based constructors for these types. See \l{qdeclarativebasictypes.html}{QML Basic Types} for more information.
274
275 \section1 Date/Time Formatters
276
277 The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
278
279 \list
280     \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
281     \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
282     \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
283 \endlist
284
285 The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
286
287
288 \section1 Dynamic Object Creation
289 The following functions on the global object allow you to dynamically create QML
290 items from files or strings. See \l{Dynamic Object Management in QML} for an overview
291 of their use.
292
293 \list
294     \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
295     \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
296 \endlist
297
298
299 \section1 Other Functions
300
301 The following functions are also on the Qt object.
302
303 \list
304     \li \l{Qt::quit()}{Qt.quit()}
305     \li \l{Qt::md5()}{Qt.md5(string)}
306     \li \l{Qt::btoa()}{string Qt.btoa(string)}
307     \li \l{Qt::atob()}{string Qt.atob(string)}
308     \li \l{Qt::binding()}{object Qt.binding(function)}
309     \li \l{Qt::locale()}{object Qt.locale()}
310     \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
311     \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
312     \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
313 \endlist
314 */
315
316 /*!
317     \qmlproperty object Qt::application
318     \since QtQuick 1.1
319
320     The \c application object provides access to global application state
321     properties shared by many QML components.
322
323     Its properties are:
324
325     \table
326     \row
327     \li \c application.active
328     \li
329     This read-only property indicates whether the application is the top-most and focused
330     application, and the user is able to interact with the application. The property
331     is false when the application is in the background, the device keylock or screen
332     saver is active, the screen backlight is turned off, or the global system dialog
333     is being displayed on top of the application. It can be used for stopping and
334     pausing animations, timers and active processing of data in order to save device
335     battery power and free device memory and processor load when the application is not
336     active.
337
338     \row
339     \li \c application.layoutDirection
340     \li
341     This read-only property can be used to query the default layout direction of the
342     application. On system start-up, the default layout direction depends on the
343     application's language. The property has a value of \c Qt.RightToLeft in locales
344     where text and graphic elements are read from right to left, and \c Qt.LeftToRight
345     where the reading direction flows from left to right. You can bind to this
346     property to customize your application layouts to support both layout directions.
347
348     Possible values are:
349
350     \list
351     \li Qt.LeftToRight - Text and graphics elements should be positioned
352                         from left to right.
353     \li Qt.RightToLeft - Text and graphics elements should be positioned
354                         from right to left.
355     \endlist
356
357     The following example uses the \c application object to indicate
358     whether the application is currently active:
359
360     \snippet doc/snippets/qml/application.qml document
361
362     \qmlproperty object Qt::inputMethod
363     \since QtQuick 2.0
364
365     The \c inputMethod object allows access to application's QInputMethod object
366     and all its properties and slots. See the QInputMethod documentation for
367     further details.
368 */
369
370
371 /*!
372 \qmlmethod object Qt::include(string url, jsobject callback)
373
374 Includes another JavaScript file. This method can only be used from within JavaScript files,
375 and not regular QML files.
376
377 This imports all functions from \a url into the current script's namespace.
378
379 Qt.include() returns an object that describes the status of the operation.  The object has
380 a single property, \c {status}, that is set to one of the following values:
381
382 \table
383 \header \li Symbol \li Value \li Description
384 \row \li result.OK \li 0 \li The include completed successfully.
385 \row \li result.LOADING \li 1 \li Data is being loaded from the network.
386 \row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
387 \row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
388 An additional \c exception property will be set in this case.
389 \endtable
390
391 The \c status property will be updated as the operation progresses.
392
393 If provided, \a callback is invoked when the operation completes.  The callback is passed
394 the same object as is returned from the Qt.include() call.
395 */
396 // Qt.include() is implemented in qv8include.cpp
397
398
399 QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
400 : propertyCapture(0), rootContext(0), isDebugging(false),
401   outputWarningsToStdErr(true), sharedContext(0), sharedScope(0),
402   cleanup(0), erroredBindings(0), inProgressCreations(0),
403   workerScriptEngine(0), activeVME(0),
404   networkAccessManager(0), networkAccessManagerFactory(0),
405   scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
406   incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
407 {
408 }
409
410 QQmlEnginePrivate::~QQmlEnginePrivate()
411 {
412     if (inProgressCreations)
413         qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
414
415     while (cleanup) {
416         QQmlCleanup *c = cleanup;
417         cleanup = c->next;
418         if (cleanup) cleanup->prev = &cleanup;
419         c->next = 0;
420         c->prev = 0;
421         c->clear();
422     }
423
424     doDeleteInEngineThread();
425
426     if (incubationController) incubationController->d = 0;
427     incubationController = 0;
428
429     delete rootContext;
430     rootContext = 0;
431
432     for(QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter)
433         (*iter)->release();
434     for(QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
435         (*iter)->release();
436     for(QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *>::Iterator iter = moduleApiInstances.begin(); iter != moduleApiInstances.end(); ++iter) {
437         delete (*iter)->qobjectApi;
438         delete *iter;
439     }
440 }
441
442 void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
443 {
444     QObjectPrivate *p = QObjectPrivate::get(o);
445     if (p->declarativeData) {
446         QQmlData *d = static_cast<QQmlData*>(p->declarativeData);
447         if (d->ownContext && d->context) {
448             d->context->destroy();
449             d->context = 0;
450         }
451
452         // Mark this object as in the process of deletion to
453         // prevent it resolving in bindings
454         QQmlData::markAsDeleted(o);
455     }
456 }
457
458 void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
459 {
460     static_cast<QQmlData *>(d)->destroyed(o);
461 }
462
463 void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
464 {
465     static_cast<QQmlData *>(d)->parentChanged(o, p);
466 }
467
468 void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int index, void **a)
469 {
470     QQmlData *ddata = QQmlData::get(object, false);
471     if (!ddata) return; // Probably being deleted
472
473     // In general, QML only supports QObject's that live on the same thread as the QQmlEngine
474     // that they're exposed to.  However, to make writing "worker objects" that calculate data
475     // in a separate thread easier, QML allows a QObject that lives in the same thread as the
476     // QQmlEngine to emit signals from a different thread.  These signals are then automatically
477     // marshalled back onto the QObject's thread and handled by QML from there.  This is tested
478     // by the qqmlecmascript::threadSignal() autotest.
479     if (ddata->notifyList &&
480         QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId) {
481
482         QMetaMethod m = object->metaObject()->method(index);
483         QList<QByteArray> parameterTypes = m.parameterTypes();
484
485         int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int));
486         void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *));
487
488         types[0] = 0; // return type
489         args[0] = 0; // return value
490
491         for (int ii = 0; ii < parameterTypes.count(); ++ii) {
492             const QByteArray &typeName = parameterTypes.at(ii);
493             if (typeName.endsWith('*'))
494                 types[ii + 1] = QMetaType::VoidStar;
495             else
496                 types[ii + 1] = QMetaType::type(typeName);
497
498             if (!types[ii + 1]) {
499                 qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
500                          "(Make sure '%s' is registered using qRegisterMetaType().)",
501                          typeName.constData(), typeName.constData());
502                 free(types);
503                 free(args);
504                 return;
505             }
506
507             args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
508         }
509
510         QMetaCallEvent *ev = new QMetaCallEvent(index, 0, 0, object, index,
511                                                 parameterTypes.count() + 1, types, args);
512         QCoreApplication::postEvent(object, ev);
513
514     } else {
515         QQmlNotifierEndpoint *ep = ddata->notify(index);
516         if (ep) QQmlNotifier::emitNotify(ep, a);
517     }
518 }
519
520 int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
521 {
522     return static_cast<QQmlData *>(d)->endpointCount(index);
523 }
524
525 int QQmlData::endpointCount(int index)
526 {
527     int count = 0;
528     QQmlNotifierEndpoint *ep = notify(index);
529     if (!ep)
530         return count;
531     ++count;
532     while (ep->next) {
533         ++count;
534         ep = ep->next;
535     }
536     return count;
537 }
538
539 void QQmlData::markAsDeleted(QObject *o)
540 {
541     QQmlData::setQueuedForDeletion(o);
542
543     QObjectPrivate *p = QObjectPrivate::get(o);
544     for (QList<QObject *>::iterator it = p->children.begin(), end = p->children.end(); it != end; ++it) {
545         QQmlData::markAsDeleted(*it);
546     }
547 }
548
549 void QQmlData::setQueuedForDeletion(QObject *object)
550 {
551     if (object) {
552         if (QObjectPrivate *priv = QObjectPrivate::get(object)) {
553             if (!priv->wasDeleted && priv->declarativeData) {
554                 QQmlData *ddata = QQmlData::get(object, false);
555                 if (ddata->ownContext && ddata->context)
556                     ddata->context->emitDestruction();
557                 ddata->isQueuedForDeletion = true;
558             }
559         }
560     }
561 }
562
563 void QQmlEnginePrivate::init()
564 {
565     Q_Q(QQmlEngine);
566
567     static bool firstTime = true;
568     if (firstTime) {
569         qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component");
570
571         QQmlData::init();
572         firstTime = false;
573     }
574
575     qRegisterMetaType<QVariant>("QVariant");
576     qRegisterMetaType<QQmlScriptString>("QQmlScriptString");
577     qRegisterMetaType<QJSValue>("QJSValue");
578     qRegisterMetaType<QQmlComponent::Status>("QQmlComponent::Status");
579     qRegisterMetaType<QList<QObject*> >("QList<QObject*>");
580     qRegisterMetaType<QList<int> >("QList<int>");
581     qRegisterMetaType<QQmlV8Handle>("QQmlV8Handle");
582
583     v8engine()->setEngine(q);
584
585     rootContext = new QQmlContext(q,true);
586
587     if (QCoreApplication::instance()->thread() == q->thread() &&
588         QQmlEngineDebugService::isDebuggingEnabled()) {
589         isDebugging = true;
590         QQmlEngineDebugService::instance()->addEngine(q);
591         QV8DebugService::initialize(v8engine());
592         QV8ProfilerService::initialize();
593         QQmlProfilerService::initialize();
594         QDebugMessageService::instance();
595     }
596
597     QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
598     if (!dataLocation.isEmpty())
599         offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
600                            + QDir::separator() + QLatin1String("QML")
601                            + QDir::separator() + QLatin1String("OfflineStorage");
602 }
603
604 QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine()
605 {
606     Q_Q(QQmlEngine);
607     if (!workerScriptEngine)
608         workerScriptEngine = new QQuickWorkerScriptEngine(q);
609     return workerScriptEngine;
610 }
611
612 /*!
613   \class QQmlEngine
614   \since 5.0
615   \inmodule QtQml
616   \brief The QQmlEngine class provides an environment for instantiating QML components.
617   \mainclass
618
619   Each QML component is instantiated in a QQmlContext.
620   QQmlContext's are essential for passing data to QML
621   components.  In QML, contexts are arranged hierarchically and this
622   hierarchy is managed by the QQmlEngine.
623
624   Prior to creating any QML components, an application must have
625   created a QQmlEngine to gain access to a QML context.  The
626   following example shows how to create a simple Text item.
627
628   \code
629   QQmlEngine engine;
630   QQmlComponent component(&engine);
631   component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
632   QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
633
634   //add item to view, etc
635   ...
636   \endcode
637
638   In this case, the Text item will be created in the engine's
639   \l {QQmlEngine::rootContext()}{root context}.
640
641   Note that the QtQuick 1 version is called QDeclarativeEngine.
642
643   \sa QQmlComponent, QQmlContext
644 */
645
646 /*!
647   Create a new QQmlEngine with the given \a parent.
648 */
649 QQmlEngine::QQmlEngine(QObject *parent)
650 : QJSEngine(*new QQmlEnginePrivate(this), parent)
651 {
652     Q_D(QQmlEngine);
653     d->init();
654 }
655
656 /*!
657   Destroys the QQmlEngine.
658
659   Any QQmlContext's created on this engine will be
660   invalidated, but not destroyed (unless they are parented to the
661   QQmlEngine object).
662 */
663 QQmlEngine::~QQmlEngine()
664 {
665     Q_D(QQmlEngine);
666     if (d->isDebugging) {
667         QQmlEngineDebugService::instance()->remEngine(this);
668     }
669
670     // Emit onDestruction signals for the root context before
671     // we destroy the contexts, engine, Module APIs etc. that
672     // may be required to handle the destruction signal.
673     QQmlContextData::get(rootContext())->emitDestruction();
674
675     // if we are the parent of any of the qobject module api instances,
676     // we need to remove them from our internal list, in order to prevent
677     // a segfault in engine private dtor.
678     QList<QQmlMetaType::ModuleApi> keys = d->moduleApiInstances.keys();
679     QObject *currQObjectApi = 0;
680     QQmlMetaType::ModuleApiInstance *currInstance = 0;
681     foreach (const QQmlMetaType::ModuleApi &key, keys) {
682         currInstance = d->moduleApiInstances.value(key);
683         currQObjectApi = currInstance->qobjectApi;
684         if (this->children().contains(currQObjectApi)) {
685             delete currQObjectApi;
686             delete currInstance;
687             d->moduleApiInstances.remove(key);
688         }
689     }
690
691     if (d->incubationController)
692         d->incubationController->d = 0;
693 }
694
695 /*! \fn void QQmlEngine::quit()
696     This signal is emitted when the QML loaded by the engine would like to quit.
697  */
698
699 /*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
700     This signal is emitted when \a warnings messages are generated by QML.
701  */
702
703 /*!
704   Clears the engine's internal component cache.
705
706   This function causes the property metadata of all components previously
707   loaded by the engine to be destroyed.  All previously loaded components and
708   the property bindings for all extant objects created from those components will
709   cease to function.
710
711   This function returns the engine to a state where it does not contain any loaded
712   component data.  This may be useful in order to reload a smaller subset of the
713   previous component set, or to load a new version of a previously loaded component.
714
715   Once the component cache has been cleared, components must be loaded before
716   any new objects can be created.
717
718   \sa trimComponentCache()
719  */
720 void QQmlEngine::clearComponentCache()
721 {
722     Q_D(QQmlEngine);
723     d->clearCache();
724 }
725
726 /*!
727   Trims the engine's internal component cache.
728
729   This function causes the property metadata of any loaded components which are
730   not currently in use to be destroyed.
731
732   A component is considered to be in use if there are any extant instances of
733   the component itself, any instances of other components that use the component,
734   or any objects instantiated by any of those components.
735
736   \sa clearComponentCache()
737  */
738 void QQmlEngine::trimComponentCache()
739 {
740     Q_D(QQmlEngine);
741     d->trimCache();
742 }
743
744 /*!
745   Returns the engine's root context.
746
747   The root context is automatically created by the QQmlEngine.
748   Data that should be available to all QML component instances
749   instantiated by the engine should be put in the root context.
750
751   Additional data that should only be available to a subset of
752   component instances should be added to sub-contexts parented to the
753   root context.
754 */
755 QQmlContext *QQmlEngine::rootContext() const
756 {
757     Q_D(const QQmlEngine);
758     return d->rootContext;
759 }
760
761 /*!
762   Sets the \a factory to use for creating QNetworkAccessManager(s).
763
764   QNetworkAccessManager is used for all network access by QML.  By
765   implementing a factory it is possible to create custom
766   QNetworkAccessManager with specialized caching, proxy and cookie
767   support.
768
769   The factory must be set before executing the engine.
770 */
771 void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
772 {
773     Q_D(QQmlEngine);
774     QMutexLocker locker(&d->mutex);
775     d->networkAccessManagerFactory = factory;
776 }
777
778 /*!
779   Returns the current QQmlNetworkAccessManagerFactory.
780
781   \sa setNetworkAccessManagerFactory()
782 */
783 QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
784 {
785     Q_D(const QQmlEngine);
786     return d->networkAccessManagerFactory;
787 }
788
789 void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
790 {
791     if (activeVME) {
792         activeVME->finalizeCallbacks.append(qMakePair(QQmlGuard<QObject>(obj), index));
793     } else {
794         void *args[] = { 0 };
795         QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
796     }
797 }
798
799 QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
800 {
801     QMutexLocker locker(&mutex);
802     QNetworkAccessManager *nam;
803     if (networkAccessManagerFactory) {
804         nam = networkAccessManagerFactory->create(parent);
805     } else {
806         nam = new QNetworkAccessManager(parent);
807     }
808
809     return nam;
810 }
811
812 QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const
813 {
814     Q_Q(const QQmlEngine);
815     if (!networkAccessManager)
816         networkAccessManager = createNetworkAccessManager(const_cast<QQmlEngine*>(q));
817     return networkAccessManager;
818 }
819
820 /*!
821   Returns a common QNetworkAccessManager which can be used by any QML
822   element instantiated by this engine.
823
824   If a QQmlNetworkAccessManagerFactory has been set and a
825   QNetworkAccessManager has not yet been created, the
826   QQmlNetworkAccessManagerFactory will be used to create the
827   QNetworkAccessManager; otherwise the returned QNetworkAccessManager
828   will have no proxy or cache set.
829
830   \sa setNetworkAccessManagerFactory()
831 */
832 QNetworkAccessManager *QQmlEngine::networkAccessManager() const
833 {
834     Q_D(const QQmlEngine);
835     return d->getNetworkAccessManager();
836 }
837
838 /*!
839
840   Sets the \a provider to use for images requested via the \e
841   image: url scheme, with host \a providerId. The QQmlEngine
842   takes ownership of \a provider.
843
844   Image providers enable support for pixmap and threaded image
845   requests. See the QQuickImageProvider documentation for details on
846   implementing and using image providers.
847
848   All required image providers should be added to the engine before any
849   QML sources files are loaded.
850
851   \sa removeImageProvider(), QQuickImageProvider, QQmlImageProviderBase
852 */
853 void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
854 {
855     Q_D(QQmlEngine);
856     QMutexLocker locker(&d->mutex);
857     d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider));
858 }
859
860 /*!
861   Returns the image provider set for \a providerId.
862
863   Returns the provider if it was found; otherwise returns 0.
864
865   \sa QQuickImageProvider
866 */
867 QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
868 {
869     Q_D(const QQmlEngine);
870     QMutexLocker locker(&d->mutex);
871     return d->imageProviders.value(providerId).data();
872 }
873
874 /*!
875   Removes the image provider for \a providerId.
876
877   \sa addImageProvider(), QQuickImageProvider
878 */
879 void QQmlEngine::removeImageProvider(const QString &providerId)
880 {
881     Q_D(QQmlEngine);
882     QMutexLocker locker(&d->mutex);
883     d->imageProviders.take(providerId);
884 }
885
886 /*!
887   Return the base URL for this engine.  The base URL is only used to
888   resolve components when a relative URL is passed to the
889   QQmlComponent constructor.
890
891   If a base URL has not been explicitly set, this method returns the
892   application's current working directory.
893
894   \sa setBaseUrl()
895 */
896 QUrl QQmlEngine::baseUrl() const
897 {
898     Q_D(const QQmlEngine);
899     if (d->baseUrl.isEmpty()) {
900         return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
901     } else {
902         return d->baseUrl;
903     }
904 }
905
906 /*!
907   Set the  base URL for this engine to \a url.
908
909   \sa baseUrl()
910 */
911 void QQmlEngine::setBaseUrl(const QUrl &url)
912 {
913     Q_D(QQmlEngine);
914     d->baseUrl = url;
915 }
916
917 /*!
918   Returns true if warning messages will be output to stderr in addition
919   to being emitted by the warnings() signal, otherwise false.
920
921   The default value is true.
922 */
923 bool QQmlEngine::outputWarningsToStandardError() const
924 {
925     Q_D(const QQmlEngine);
926     return d->outputWarningsToStdErr;
927 }
928
929 /*!
930   Set whether warning messages will be output to stderr to \a enabled.
931
932   If \a enabled is true, any warning messages generated by QML will be
933   output to stderr and emitted by the warnings() signal.  If \a enabled
934   is false, on the warnings() signal will be emitted.  This allows
935   applications to handle warning output themselves.
936
937   The default value is true.
938 */
939 void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
940 {
941     Q_D(QQmlEngine);
942     d->outputWarningsToStdErr = enabled;
943 }
944
945 /*!
946   Attempt to free unused memory.
947 */
948 void QQmlEngine::collectGarbage()
949 {
950     QV8Engine::gc();
951 }
952
953 /*!
954   Returns the QQmlContext for the \a object, or 0 if no
955   context has been set.
956
957   When the QQmlEngine instantiates a QObject, the context is
958   set automatically.
959   */
960 QQmlContext *QQmlEngine::contextForObject(const QObject *object)
961 {
962     if(!object)
963         return 0;
964
965     QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
966
967     QQmlData *data =
968         static_cast<QQmlData *>(priv->declarativeData);
969
970     if (!data)
971         return 0;
972     else if (data->outerContext)
973         return data->outerContext->asQQmlContext();
974     else
975         return 0;
976 }
977
978 /*!
979   Sets the QQmlContext for the \a object to \a context.
980   If the \a object already has a context, a warning is
981   output, but the context is not changed.
982
983   When the QQmlEngine instantiates a QObject, the context is
984   set automatically.
985  */
986 void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
987 {
988     if (!object || !context)
989         return;
990
991     QQmlData *data = QQmlData::get(object, true);
992     if (data->context) {
993         qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext");
994         return;
995     }
996
997     QQmlContextData *contextData = QQmlContextData::get(context);
998     contextData->addObject(object);
999 }
1000
1001 /*!
1002   \enum QQmlEngine::ObjectOwnership
1003
1004   Ownership controls whether or not QML automatically destroys the
1005   QObject when the object is garbage collected by the JavaScript
1006   engine.  The two ownership options are:
1007
1008   \value CppOwnership The object is owned by C++ code, and will
1009   never be deleted by QML.  The JavaScript destroy() method cannot be
1010   used on objects with CppOwnership.  This option is similar to
1011   QScriptEngine::QtOwnership.
1012
1013   \value JavaScriptOwnership The object is owned by JavaScript.
1014   When the object is returned to QML as the return value of a method
1015   call or property access, QML will track it, and delete the object
1016   if there are no remaining JavaScript references to it and it has no
1017   QObject::parent().  An object tracked by one QQmlEngine
1018   will be deleted during that QQmlEngine's destructor, and thus
1019   JavaScript references between objects with JavaScriptOwnership from
1020   two different engines will not be valid after the deletion of one of
1021   those engines.  This option is similar to QScriptEngine::ScriptOwnership.
1022
1023   Generally an application doesn't need to set an object's ownership
1024   explicitly.  QML uses a heuristic to set the default object
1025   ownership.  By default, an object that is created by QML has
1026   JavaScriptOwnership.  The exception to this are the root objects
1027   created by calling QQmlComponent::create() or
1028   QQmlComponent::beginCreate() which have CppOwnership by
1029   default.  The ownership of these root-level objects is considered to
1030   have been transferred to the C++ caller.
1031
1032   Objects not-created by QML have CppOwnership by default.  The
1033   exception to this is objects returned from a C++ method call.  The
1034   ownership of these objects is passed to JavaScript.
1035
1036   Calling setObjectOwnership() overrides the default ownership
1037   heuristic used by QML.
1038 */
1039
1040 /*!
1041   Sets the \a ownership of \a object.
1042 */
1043 void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
1044 {
1045     if (!object)
1046         return;
1047
1048     QQmlData *ddata = QQmlData::get(object, true);
1049     if (!ddata)
1050         return;
1051
1052     ddata->indestructible = (ownership == CppOwnership)?true:false;
1053     ddata->explicitIndestructibleSet = true;
1054 }
1055
1056 /*!
1057   Returns the ownership of \a object.
1058 */
1059 QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
1060 {
1061     if (!object)
1062         return CppOwnership;
1063
1064     QQmlData *ddata = QQmlData::get(object, false);
1065     if (!ddata)
1066         return CppOwnership;
1067     else
1068         return ddata->indestructible?CppOwnership:JavaScriptOwnership;
1069 }
1070
1071 bool QQmlEngine::event(QEvent *e)
1072 {
1073     Q_D(QQmlEngine);
1074     if (e->type() == QEvent::User)
1075         d->doDeleteInEngineThread();
1076
1077     return QJSEngine::event(e);
1078 }
1079
1080 void QQmlEnginePrivate::doDeleteInEngineThread()
1081 {
1082     QFieldList<Deletable, &Deletable::next> list;
1083     mutex.lock();
1084     list.copyAndClear(toDeleteInEngineThread);
1085     mutex.unlock();
1086
1087     while (Deletable *d = list.takeFirst())
1088         delete d;
1089 }
1090
1091 Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object)
1092 {
1093     QQmlData *data = QQmlData::get(object);
1094
1095     if (data && data->compiledData && data->deferredIdx) {
1096         QQmlObjectCreatingProfiler prof;
1097         if (prof.enabled) {
1098             QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
1099             prof.setTypeName(type ? type->qmlTypeName()
1100                                   : QString::fromUtf8(object->metaObject()->className()));
1101             if (data->outerContext)
1102                 prof.setLocation(data->outerContext->url, data->lineNumber, data->columnNumber);
1103         }
1104         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
1105
1106         QQmlComponentPrivate::ConstructionState state;
1107         QQmlComponentPrivate::beginDeferred(ep, object, &state);
1108
1109         // Release the reference for the deferral action (we still have one from construction)
1110         data->compiledData->release();
1111         data->compiledData = 0;
1112
1113         QQmlComponentPrivate::complete(ep, &state);
1114     }
1115 }
1116
1117 QQmlContext *qmlContext(const QObject *obj)
1118 {
1119     return QQmlEngine::contextForObject(obj);
1120 }
1121
1122 QQmlEngine *qmlEngine(const QObject *obj)
1123 {
1124     QQmlData *data = QQmlData::get(obj, false);
1125     if (!data || !data->context)
1126         return 0;
1127     return data->context->engine;
1128 }
1129
1130 QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
1131 {
1132     QQmlData *data = QQmlData::get(object);
1133     if (!data)
1134         return 0; // Attached properties are only on objects created by QML
1135
1136     QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
1137     if (rv || !create)
1138         return rv;
1139
1140     QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(id);
1141     if (!pf)
1142         return 0;
1143
1144     rv = pf(const_cast<QObject *>(object));
1145
1146     if (rv)
1147         data->attachedProperties()->insert(id, rv);
1148
1149     return rv;
1150 }
1151
1152 QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1153                                      const QMetaObject *attachedMetaObject, bool create)
1154 {
1155     if (*idCache == -1)
1156         *idCache = QQmlMetaType::attachedPropertiesFuncId(attachedMetaObject);
1157
1158     if (*idCache == -1 || !object)
1159         return 0;
1160
1161     return qmlAttachedPropertiesObjectById(*idCache, object, create);
1162 }
1163
1164 QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
1165 {
1166 #ifndef QQML_NO_DEBUG_PROTOCOL
1167     if (!QQmlEnginePrivate::qml_debugging_enabled
1168             && printWarning) {
1169         qDebug("QML debugging is enabled. Only use this in a safe environment.");
1170     }
1171     QQmlEnginePrivate::qml_debugging_enabled = true;
1172 #endif
1173 }
1174
1175
1176 class QQmlDataExtended {
1177 public:
1178     QQmlDataExtended();
1179     ~QQmlDataExtended();
1180
1181     QHash<int, QObject *> attachedProperties;
1182 };
1183
1184 QQmlDataExtended::QQmlDataExtended()
1185 {
1186 }
1187
1188 QQmlDataExtended::~QQmlDataExtended()
1189 {
1190 }
1191
1192 void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint)
1193 {
1194     if (endpoint->next)
1195         layout(endpoint->next);
1196
1197     int index = endpoint->sourceSignal;
1198     index = qMin(index, 0xFFFF - 1);
1199
1200     endpoint->next = notifies[index];
1201     if (endpoint->next) endpoint->next->prev = &endpoint->next;
1202     endpoint->prev = &notifies[index];
1203     notifies[index] = endpoint;
1204 }
1205
1206 void QQmlData::NotifyList::layout()
1207 {
1208     Q_ASSERT(maximumTodoIndex >= notifiesSize);
1209
1210     if (todo) {
1211         QQmlNotifierEndpoint **old = notifies;
1212         const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*);
1213         notifies = (QQmlNotifierEndpoint**)realloc(notifies, reallocSize);
1214         const int memsetSize = (maximumTodoIndex - notifiesSize + 1) *
1215                                sizeof(QQmlNotifierEndpoint*);
1216         memset(notifies + notifiesSize, 0, memsetSize);
1217
1218         if (notifies != old) {
1219             for (int ii = 0; ii < notifiesSize; ++ii)
1220                 if (notifies[ii])
1221                     notifies[ii]->prev = &notifies[ii];
1222         }
1223
1224         notifiesSize = maximumTodoIndex + 1;
1225
1226         layout(todo);
1227     }
1228
1229     maximumTodoIndex = 0;
1230     todo = 0;
1231 }
1232
1233 void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
1234 {
1235     if (!notifyList) {
1236         notifyList = (NotifyList *)malloc(sizeof(NotifyList));
1237         notifyList->connectionMask = 0;
1238         notifyList->maximumTodoIndex = 0;
1239         notifyList->notifiesSize = 0;
1240         notifyList->todo = 0;
1241         notifyList->notifies = 0;
1242     }
1243
1244     Q_ASSERT(!endpoint->isConnected());
1245
1246     index = qMin(index, 0xFFFF - 1);
1247     notifyList->connectionMask |= (1ULL << quint64(index % 64));
1248
1249     if (index < notifyList->notifiesSize) {
1250
1251         endpoint->next = notifyList->notifies[index];
1252         if (endpoint->next) endpoint->next->prev = &endpoint->next;
1253         endpoint->prev = &notifyList->notifies[index];
1254         notifyList->notifies[index] = endpoint;
1255
1256     } else {
1257         notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
1258
1259         endpoint->next = notifyList->todo;
1260         if (endpoint->next) endpoint->next->prev = &endpoint->next;
1261         endpoint->prev = &notifyList->todo;
1262         notifyList->todo = endpoint;
1263     }
1264 }
1265
1266 bool QQml_isSignalConnected(QObject *obj, int signal_index, int index)
1267 {
1268     QQmlData *data = QQmlData::get(obj);
1269     return QObjectPrivate::get(obj)->isSignalConnected(signal_index) || (data && data->signalHasEndpoint(index));
1270 }
1271
1272 /*
1273     index MUST be the index returned by QMetaMethod::index()
1274     This is different than the index returned by QObjectPrivate::signalIndex()
1275 */
1276 bool QQmlData::signalHasEndpoint(int index)
1277 {
1278     return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
1279 }
1280
1281 QHash<int, QObject *> *QQmlData::attachedProperties() const
1282 {
1283     if (!extendedData) extendedData = new QQmlDataExtended;
1284     return &extendedData->attachedProperties;
1285 }
1286
1287 void QQmlData::destroyed(QObject *object)
1288 {
1289     if (nextContextObject)
1290         nextContextObject->prevContextObject = prevContextObject;
1291     if (prevContextObject)
1292         *prevContextObject = nextContextObject;
1293
1294     QQmlAbstractBinding *binding = bindings;
1295     while (binding) {
1296         QQmlAbstractBinding *next = binding->m_nextBinding;
1297         binding->m_prevBinding = 0;
1298         binding->m_nextBinding = 0;
1299         binding->destroy();
1300         binding = next;
1301     }
1302
1303     if (compiledData) {
1304         compiledData->release();
1305         compiledData = 0;
1306     }
1307
1308     QQmlAbstractBoundSignal *signalHandler = signalHandlers;
1309     while (signalHandler) {
1310         if (signalHandler->isEvaluating()) {
1311             // The object is being deleted during signal handler evaluation.
1312             // This will cause a crash due to invalid memory access when the
1313             // evaluation has completed.
1314             // Abort with a friendly message instead.
1315             QString locationString;
1316             QQmlBoundSignalExpression *expr = signalHandler->expression();
1317             if (expr) {
1318                 QString fileName = expr->sourceFile();
1319                 if (fileName.isEmpty())
1320                     fileName = QStringLiteral("<Unknown File>");
1321                 locationString.append(fileName);
1322                 locationString.append(QString::fromLatin1(":%0: ").arg(expr->lineNumber()));
1323                 QString source = expr->expression();
1324                 if (source.size() > 100) {
1325                     source.truncate(96);
1326                     source.append(QStringLiteral(" ..."));
1327                 }
1328                 locationString.append(source);
1329             } else {
1330                 locationString = QStringLiteral("<Unknown Location>");
1331             }
1332             qFatal("Object %p destroyed while one of its QML signal handlers is in progress.\n"
1333                    "Most likely the object was deleted synchronously (use QObject::deleteLater() "
1334                    "instead), or the application is running a nested event loop.\n"
1335                    "This behavior is NOT supported!\n"
1336                    "%s", object, qPrintable(locationString));
1337         }
1338
1339         QQmlAbstractBoundSignal *next = signalHandler->m_nextSignal;
1340         signalHandler->m_prevSignal = 0;
1341         signalHandler->m_nextSignal = 0;
1342         delete signalHandler;
1343         signalHandler = next;
1344     }
1345
1346     if (bindingBits)
1347         free(bindingBits);
1348
1349     if (propertyCache)
1350         propertyCache->release();
1351
1352     if (ownContext && context)
1353         context->destroy();
1354
1355     while (guards) {
1356         QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
1357         *guard = (QObject *)0;
1358         guard->objectDestroyed(object);
1359     }
1360
1361     if (notifyList) {
1362         while (notifyList->todo)
1363             notifyList->todo->disconnect();
1364         for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
1365             while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
1366                 ep->disconnect();
1367         }
1368         free(notifyList->notifies);
1369         free(notifyList);
1370         notifyList = 0;
1371     }
1372
1373     if (extendedData)
1374         delete extendedData;
1375
1376     // Dispose the handle.
1377     // We don't simply clear it (and wait for next gc cycle to dispose
1378     // via the weak qobject reference callback) as this affects the
1379     // outcomes of v8's gc statistical analysis heuristics, which can
1380     // cause unnecessary growth of the old pointer space js heap area.
1381     qPersistentDispose(v8object);
1382
1383     if (ownMemory)
1384         delete this;
1385 }
1386
1387 void QQmlData::parentChanged(QObject *object, QObject *parent)
1388 {
1389     Q_UNUSED(object);
1390     Q_UNUSED(parent);
1391 }
1392
1393 bool QQmlData::hasBindingBit(int bit) const
1394 {
1395     if (bindingBitsSize > bit)
1396         return bindingBits[bit / 32] & (1 << (bit % 32));
1397     else
1398         return false;
1399 }
1400
1401 void QQmlData::clearBindingBit(int bit)
1402 {
1403     if (bindingBitsSize > bit)
1404         bindingBits[bit / 32] &= ~(1 << (bit % 32));
1405 }
1406
1407 void QQmlData::setBindingBit(QObject *obj, int bit)
1408 {
1409     if (bindingBitsSize <= bit) {
1410         int props = obj->metaObject()->propertyCount();
1411         Q_ASSERT(bit < props);
1412
1413         int arraySize = (props + 31) / 32;
1414         int oldArraySize = bindingBitsSize / 32;
1415
1416         bindingBits = (quint32 *)realloc(bindingBits,
1417                                          arraySize * sizeof(quint32));
1418
1419         memset(bindingBits + oldArraySize,
1420                0x00,
1421                sizeof(quint32) * (arraySize - oldArraySize));
1422
1423         bindingBitsSize = arraySize * 32;
1424     }
1425
1426     bindingBits[bit / 32] |= (1 << (bit % 32));
1427 }
1428
1429 void QQmlEnginePrivate::sendQuit()
1430 {
1431     Q_Q(QQmlEngine);
1432     emit q->quit();
1433     if (q->receivers(SIGNAL(quit())) == 0) {
1434         qWarning("Signal QQmlEngine::quit() emitted, but no receivers connected to handle it.");
1435     }
1436 }
1437
1438 static void dumpwarning(const QQmlError &error)
1439 {
1440     QMessageLogger(error.url().toString().toLatin1().constData(),
1441                    error.line(), 0).warning().nospace()
1442             << qPrintable(error.toString());
1443 }
1444
1445 static void dumpwarning(const QList<QQmlError> &errors)
1446 {
1447     for (int ii = 0; ii < errors.count(); ++ii)
1448         dumpwarning(errors.at(ii));
1449 }
1450
1451 void QQmlEnginePrivate::warning(const QQmlError &error)
1452 {
1453     Q_Q(QQmlEngine);
1454     q->warnings(QList<QQmlError>() << error);
1455     if (outputWarningsToStdErr)
1456         dumpwarning(error);
1457 }
1458
1459 void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
1460 {
1461     Q_Q(QQmlEngine);
1462     q->warnings(errors);
1463     if (outputWarningsToStdErr)
1464         dumpwarning(errors);
1465 }
1466
1467 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
1468 {
1469     if (engine)
1470         QQmlEnginePrivate::get(engine)->warning(error);
1471     else
1472         dumpwarning(error);
1473 }
1474
1475 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &error)
1476 {
1477     if (engine)
1478         QQmlEnginePrivate::get(engine)->warning(error);
1479     else
1480         dumpwarning(error);
1481 }
1482
1483 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
1484 {
1485     if (engine)
1486         engine->warning(error);
1487     else
1488         dumpwarning(error);
1489 }
1490
1491 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError> &error)
1492 {
1493     if (engine)
1494         engine->warning(error);
1495     else
1496         dumpwarning(error);
1497 }
1498
1499 /*
1500    This function should be called prior to evaluation of any js expression,
1501    so that scarce resources are not freed prematurely (eg, if there is a
1502    nested javascript expression).
1503  */
1504 void QQmlEnginePrivate::referenceScarceResources()
1505 {
1506     scarceResourcesRefCount += 1;
1507 }
1508
1509 /*
1510    This function should be called after evaluation of the js expression is
1511    complete, and so the scarce resources may be freed safely.
1512  */
1513 void QQmlEnginePrivate::dereferenceScarceResources()
1514 {
1515     Q_ASSERT(scarceResourcesRefCount > 0);
1516     scarceResourcesRefCount -= 1;
1517
1518     // if the refcount is zero, then evaluation of the "top level"
1519     // expression must have completed.  We can safely release the
1520     // scarce resources.
1521     if (scarceResourcesRefCount == 0) {
1522         // iterate through the list and release them all.
1523         // note that the actual SRD is owned by the JS engine,
1524         // so we cannot delete the SRD; but we can free the
1525         // memory used by the variant in the SRD.
1526         while (ScarceResourceData *sr = scarceResources.first()) {
1527             sr->data = QVariant();
1528             scarceResources.remove(sr);
1529         }
1530     }
1531 }
1532
1533 /*!
1534   Adds \a path as a directory where the engine searches for
1535   installed modules in a URL-based directory structure.
1536   The \a path may be a local filesystem directory or a URL.
1537
1538   The newly added \a path will be first in the importPathList().
1539
1540   \sa setImportPathList(), {QML Modules}
1541 */
1542 void QQmlEngine::addImportPath(const QString& path)
1543 {
1544     Q_D(QQmlEngine);
1545     d->importDatabase.addImportPath(path);
1546 }
1547
1548 /*!
1549   Returns the list of directories where the engine searches for
1550   installed modules in a URL-based directory structure.
1551
1552   For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
1553   imports \c com.mycompany.Feature will cause the QQmlEngine to look
1554   in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
1555   provided by that module. A \c qmldir file is required for defining the
1556   type version mapping and possibly QML extensions plugins.
1557
1558   By default, the list contains the directory of the application executable,
1559   paths specified in the \c QML_IMPORT_PATH environment variable,
1560   and the builtin \c ImportsPath from QLibraryInfo.
1561
1562   \sa addImportPath(), setImportPathList()
1563 */
1564 QStringList QQmlEngine::importPathList() const
1565 {
1566     Q_D(const QQmlEngine);
1567     return d->importDatabase.importPathList();
1568 }
1569
1570 /*!
1571   Sets \a paths as the list of directories where the engine searches for
1572   installed modules in a URL-based directory structure.
1573
1574   By default, the list contains the directory of the application executable,
1575   paths specified in the \c QML_IMPORT_PATH environment variable,
1576   and the builtin \c ImportsPath from QLibraryInfo.
1577
1578   \sa importPathList(), addImportPath()
1579   */
1580 void QQmlEngine::setImportPathList(const QStringList &paths)
1581 {
1582     Q_D(QQmlEngine);
1583     d->importDatabase.setImportPathList(paths);
1584 }
1585
1586
1587 /*!
1588   Adds \a path as a directory where the engine searches for
1589   native plugins for imported modules (referenced in the \c qmldir file).
1590
1591   By default, the list contains only \c .,  i.e. the engine searches
1592   in the directory of the \c qmldir file itself.
1593
1594   The newly added \a path will be first in the pluginPathList().
1595
1596   \sa setPluginPathList()
1597 */
1598 void QQmlEngine::addPluginPath(const QString& path)
1599 {
1600     Q_D(QQmlEngine);
1601     d->importDatabase.addPluginPath(path);
1602 }
1603
1604
1605 /*!
1606   Returns the list of directories where the engine searches for
1607   native plugins for imported modules (referenced in the \c qmldir file).
1608
1609   By default, the list contains only \c .,  i.e. the engine searches
1610   in the directory of the \c qmldir file itself.
1611
1612   \sa addPluginPath(), setPluginPathList()
1613 */
1614 QStringList QQmlEngine::pluginPathList() const
1615 {
1616     Q_D(const QQmlEngine);
1617     return d->importDatabase.pluginPathList();
1618 }
1619
1620 /*!
1621   Sets the list of directories where the engine searches for
1622   native plugins for imported modules (referenced in the \c qmldir file)
1623   to \a paths.
1624
1625   By default, the list contains only \c .,  i.e. the engine searches
1626   in the directory of the \c qmldir file itself.
1627
1628   \sa pluginPathList(), addPluginPath()
1629   */
1630 void QQmlEngine::setPluginPathList(const QStringList &paths)
1631 {
1632     Q_D(QQmlEngine);
1633     d->importDatabase.setPluginPathList(paths);
1634 }
1635
1636 /*!
1637   Imports the plugin named \a filePath with the \a uri provided.
1638   Returns true if the plugin was successfully imported; otherwise returns false.
1639
1640   On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
1641
1642   The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
1643 */
1644 bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
1645 {
1646     Q_D(QQmlEngine);
1647     return d->importDatabase.importPlugin(filePath, uri, errors);
1648 }
1649
1650 /*!
1651   Imports the plugin named \a filePath with the \a uri provided.
1652   Returns true if the plugin was successfully imported; otherwise returns false.
1653
1654   On failure and if non-null, *\a errorString will be set to a message describing the failure.
1655
1656   The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
1657 */
1658 bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
1659 {
1660     Q_D(QQmlEngine);
1661     QList<QQmlError> errors;
1662     bool retn = d->importDatabase.importPlugin(filePath, uri, &errors);
1663     if (!errors.isEmpty()) {
1664         QString builtError;
1665         for (int i = 0; i < errors.size(); ++i) {
1666             builtError = QString(QLatin1String("%1\n        %2"))
1667                     .arg(builtError)
1668                     .arg(errors.at(i).toString());
1669         }
1670         *errorString = builtError;
1671     }
1672     return retn;
1673 }
1674
1675 /*!
1676   \property QQmlEngine::offlineStoragePath
1677   \brief the directory for storing offline user data
1678
1679   Returns the directory where SQL and other offline
1680   storage is placed.
1681
1682   QQuickWebView and the SQL databases created with openDatabase()
1683   are stored here.
1684
1685   The default is QML/OfflineStorage in the platform-standard
1686   user application data directory.
1687
1688   Note that the path may not currently exist on the filesystem, so
1689   callers wanting to \e create new files at this location should create
1690   it first - see QDir::mkpath().
1691 */
1692 void QQmlEngine::setOfflineStoragePath(const QString& dir)
1693 {
1694     Q_D(QQmlEngine);
1695     d->offlineStoragePath = dir;
1696 }
1697
1698 QString QQmlEngine::offlineStoragePath() const
1699 {
1700     Q_D(const QQmlEngine);
1701     return d->offlineStoragePath;
1702 }
1703
1704 QQmlPropertyCache *QQmlEnginePrivate::createCache(const QMetaObject *mo)
1705 {
1706     Q_Q(QQmlEngine);
1707
1708     if (!mo->superClass()) {
1709         QQmlPropertyCache *rv = new QQmlPropertyCache(q, mo);
1710         propertyCache.insert(mo, rv);
1711         return rv;
1712     } else {
1713         QQmlPropertyCache *super = cache(mo->superClass());
1714         QQmlPropertyCache *rv = super->copyAndAppend(q, mo);
1715         propertyCache.insert(mo, rv);
1716         return rv;
1717     }
1718 }
1719
1720 QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion,
1721                                                                   QQmlError &error)
1722 {
1723     QList<QQmlType *> types;
1724
1725     int maxMinorVersion = 0;
1726
1727     const QMetaObject *metaObject = type->metaObject();
1728
1729     while (metaObject) {
1730         QQmlType *t = QQmlMetaType::qmlType(metaObject, type->module(),
1731                                                             type->majorVersion(), minorVersion);
1732         if (t) {
1733             maxMinorVersion = qMax(maxMinorVersion, t->minorVersion());
1734             types << t;
1735         } else {
1736             types << 0;
1737         }
1738
1739         metaObject = metaObject->superClass();
1740     }
1741
1742     if (QQmlPropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) {
1743         c->addref();
1744         typePropertyCache.insert(qMakePair(type, minorVersion), c);
1745         return c;
1746     }
1747
1748     QQmlPropertyCache *raw = cache(type->metaObject());
1749
1750     bool hasCopied = false;
1751
1752     for (int ii = 0; ii < types.count(); ++ii) {
1753         QQmlType *currentType = types.at(ii);
1754         if (!currentType)
1755             continue;
1756
1757         int rev = currentType->metaObjectRevision();
1758         int moIndex = types.count() - 1 - ii;
1759
1760         if (raw->allowedRevisionCache[moIndex] != rev) {
1761             if (!hasCopied) {
1762                 raw = raw->copy();
1763                 hasCopied = true;
1764             }
1765             raw->allowedRevisionCache[moIndex] = rev;
1766         }
1767     }
1768
1769     // Test revision compatibility - the basic rule is:
1770     //    * Anything that is excluded, cannot overload something that is not excluded *
1771
1772     // Signals override:
1773     //    * other signals and methods of the same name.
1774     //    * properties named on<Signal Name>
1775     //    * automatic <property name>Changed notify signals
1776
1777     // Methods override:
1778     //    * other methods of the same name
1779
1780     // Properties override:
1781     //    * other elements of the same name
1782
1783     bool overloadError = false;
1784     QString overloadName;
1785
1786 #if 0
1787     for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
1788          !overloadError && iter != raw->stringCache.end();
1789          ++iter) {
1790
1791         QQmlPropertyData *d = *iter;
1792         if (raw->isAllowedInRevision(d))
1793             continue; // Not excluded - no problems
1794
1795         // check that a regular "name" overload isn't happening
1796         QQmlPropertyData *current = d;
1797         while (!overloadError && current) {
1798             current = d->overrideData(current);
1799             if (current && raw->isAllowedInRevision(current))
1800                 overloadError = true;
1801         }
1802     }
1803 #endif
1804
1805     if (overloadError) {
1806         if (hasCopied) raw->release();
1807
1808         error.setDescription(QLatin1String("Type ") + type->qmlTypeName() + QLatin1Char(' ') + QString::number(type->majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\".  This is an error in the type's implementation."));
1809         return 0;
1810     }
1811
1812     if (!hasCopied) raw->addref();
1813     typePropertyCache.insert(qMakePair(type, minorVersion), raw);
1814
1815     if (minorVersion != maxMinorVersion) {
1816         raw->addref();
1817         typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw);
1818     }
1819
1820     return raw;
1821 }
1822
1823 QQmlMetaType::ModuleApiInstance *
1824 QQmlEnginePrivate::moduleApiInstance(const QQmlMetaType::ModuleApi &module)
1825 {
1826     Locker locker(this);
1827
1828     QQmlMetaType::ModuleApiInstance *a = moduleApiInstances.value(module);
1829     if (!a) {
1830         a = new QQmlMetaType::ModuleApiInstance;
1831         a->scriptCallback = module.script;
1832         a->qobjectCallback = module.qobject;
1833         a->instanceMetaObject = module.instanceMetaObject;
1834         moduleApiInstances.insert(module, a);
1835     }
1836
1837     return a;
1838 }
1839
1840 bool QQmlEnginePrivate::isQObject(int t)
1841 {
1842     Locker locker(this);
1843     return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t);
1844 }
1845
1846 QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
1847 {
1848     Locker locker(this);
1849     int t = v.userType();
1850     if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
1851         if (ok) *ok = true;
1852         return *(QObject **)(v.constData());
1853     } else {
1854         return QQmlMetaType::toQObject(v, ok);
1855     }
1856 }
1857
1858 QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
1859 {
1860     Locker locker(this);
1861     if (m_compositeTypes.contains(t))
1862         return QQmlMetaType::Object;
1863     else if (m_qmlLists.contains(t))
1864         return QQmlMetaType::List;
1865     else
1866         return QQmlMetaType::typeCategory(t);
1867 }
1868
1869 bool QQmlEnginePrivate::isList(int t) const
1870 {
1871     Locker locker(this);
1872     return m_qmlLists.contains(t) || QQmlMetaType::isList(t);
1873 }
1874
1875 int QQmlEnginePrivate::listType(int t) const
1876 {
1877     Locker locker(this);
1878     QHash<int, int>::ConstIterator iter = m_qmlLists.find(t);
1879     if (iter != m_qmlLists.end())
1880         return *iter;
1881     else
1882         return QQmlMetaType::listType(t);
1883 }
1884
1885 const QMetaObject *QQmlEnginePrivate::rawMetaObjectForType(int t) const
1886 {
1887     Locker locker(this);
1888     QHash<int, const QMetaObject *>::ConstIterator iter = m_compositeTypes.find(t);
1889     if (iter != m_compositeTypes.end()) {
1890         return *iter;
1891     } else {
1892         QQmlType *type = QQmlMetaType::qmlType(t);
1893         return type?type->baseMetaObject():0;
1894     }
1895 }
1896
1897 const QMetaObject *QQmlEnginePrivate::metaObjectForType(int t) const
1898 {
1899     Locker locker(this);
1900     QHash<int, const QMetaObject *>::ConstIterator iter = m_compositeTypes.find(t);
1901     if (iter != m_compositeTypes.end()) {
1902         return *iter;
1903     } else {
1904         QQmlType *type = QQmlMetaType::qmlType(t);
1905         return type?type->metaObject():0;
1906     }
1907 }
1908
1909 void QQmlEnginePrivate::registerCompositeType(const QMetaObject *mo)
1910 {
1911     QByteArray name = mo->className();
1912
1913     QByteArray ptr = name + '*';
1914     QByteArray lst = "QQmlListProperty<" + name + '>';
1915
1916     int ptr_type = QMetaType::registerNormalizedType(ptr,
1917                                                      qMetaTypeDeleteHelper<QObject*>,
1918                                                      qMetaTypeCreateHelper<QObject*>,
1919                                                      qMetaTypeDestructHelper<QObject*>,
1920                                                      qMetaTypeConstructHelper<QObject*>,
1921                                                      sizeof(QObject*),
1922                                                      static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags),
1923                                                      mo);
1924     int lst_type = QMetaType::registerNormalizedType(lst,
1925                                                      qMetaTypeDeleteHelper<QQmlListProperty<QObject> >,
1926                                                      qMetaTypeCreateHelper<QQmlListProperty<QObject> >,
1927                                                      qMetaTypeDestructHelper<QQmlListProperty<QObject> >,
1928                                                      qMetaTypeConstructHelper<QQmlListProperty<QObject> >,
1929                                                      sizeof(QQmlListProperty<QObject>),
1930                                                      static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
1931                                                      static_cast<QMetaObject*>(0));
1932
1933     Locker locker(this);
1934     m_qmlLists.insert(lst_type, ptr_type);
1935     m_compositeTypes.insert(ptr_type, mo);
1936 }
1937
1938 void QQmlEnginePrivate::unregisterCompositeType(const QMetaObject *mo)
1939 {
1940     QByteArray name = mo->className();
1941
1942     QByteArray ptr = name + '*';
1943     QByteArray lst = "QQmlListProperty<" + name + '>';
1944
1945     int ptr_type = QMetaType::type(ptr.constData());
1946     int lst_type = QMetaType::type(lst.constData());
1947
1948     Locker locker(this);
1949     m_qmlLists.remove(lst_type);
1950     m_compositeTypes.remove(ptr_type);
1951 }
1952
1953 void QQmlEnginePrivate::clearCache()
1954 {
1955     typeLoader.clearCache(this, &QQmlEnginePrivate::typeUnloaded);
1956 }
1957
1958 void QQmlEnginePrivate::trimCache()
1959 {
1960     typeLoader.trimCache(this, &QQmlEnginePrivate::typeUnloaded);
1961 }
1962
1963 void QQmlEnginePrivate::typeUnloaded(QQmlTypeData *typeData)
1964 {
1965     unregisterCompositeType(typeData->compiledData()->root);
1966 }
1967
1968 bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
1969 {
1970     return typeLoader.isTypeLoaded(url);
1971 }
1972
1973 bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
1974 {
1975     return typeLoader.isScriptLoaded(url);
1976 }
1977
1978 bool QQml_isFileCaseCorrect(const QString &fileName)
1979 {
1980 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
1981     QFileInfo info(fileName);
1982     const QString absolute = info.absoluteFilePath();
1983
1984 #if defined(Q_OS_MAC)
1985     const QString canonical = info.canonicalFilePath();
1986 #elif defined(Q_OS_WIN)
1987     wchar_t buffer[1024];
1988
1989     DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024);
1990     if (rv == 0 || rv >= 1024) return true;
1991     rv = ::GetLongPathName(buffer, buffer, 1024);
1992     if (rv == 0 || rv >= 1024) return true;
1993
1994     const QString canonical = QString::fromWCharArray(buffer);
1995 #endif
1996
1997     const int absoluteLength = absolute.length();
1998     const int canonicalLength = canonical.length();
1999
2000     const int length = qMin(absoluteLength, canonicalLength);
2001     for (int ii = 0; ii < length; ++ii) {
2002         const QChar &a = absolute.at(absoluteLength - 1 - ii);
2003         const QChar &c = canonical.at(canonicalLength - 1 - ii);
2004
2005         if (a.toLower() != c.toLower())
2006             return true;
2007         if (a != c)
2008             return false;
2009     }
2010 #else
2011     Q_UNUSED(fileName)
2012 #endif
2013     return true;
2014 }
2015
2016 /*!
2017     \fn QQmlEngine *qmlEngine(const QObject *object)
2018     \relates QQmlEngine
2019
2020     Returns the QQmlEngine associated with \a object, if any.  This is equivalent to
2021     QQmlEngine::contextForObject(object)->engine(), but more efficient.
2022 */
2023
2024 /*!
2025     \fn QQmlContext *qmlContext(const QObject *object)
2026     \relates QQmlEngine
2027
2028     Returns the QQmlContext associated with \a object, if any.  This is equivalent to
2029     QQmlEngine::contextForObject(object).
2030 */
2031
2032 QT_END_NAMESPACE