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