1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qqmlengine_p.h"
41 #include "qqmlengine.h"
42 #include "qqmlcomponentattached_p.h"
43 
44 #include "qqmlcontext_p.h"
45 #include "qqml.h"
46 #include "qqmlcontext.h"
47 #include "qqmlexpression.h"
48 #include "qqmlcomponent.h"
49 #include "qqmlvme_p.h"
50 #include "qqmlstringconverters_p.h"
51 #include "qqmlscriptstring.h"
52 #include "qqmlglobal_p.h"
53 #include "qqmlcomponent_p.h"
54 #include "qqmlextensioninterface.h"
55 #include "qqmllist_p.h"
56 #include "qqmltypenamecache_p.h"
57 #include "qqmlnotifier_p.h"
58 #include "qqmlincubator.h"
59 #include "qqmlabstracturlinterceptor.h"
60 #include "qqmlsourcecoordinate_p.h"
61 #include <private/qqmldirparser_p.h>
62 #include <private/qqmlboundsignal_p.h>
63 #include <private/qqmljsdiagnosticmessage_p.h>
64 #include <QtCore/qstandardpaths.h>
65 #include <QtCore/qsettings.h>
66 #include <QtCore/qmetaobject.h>
67 #include <QDebug>
68 #include <QtCore/qcoreapplication.h>
69 #include <QtCore/qcryptographichash.h>
70 #include <QtCore/qdir.h>
71 #include <QtCore/qmutex.h>
72 #include <QtCore/qthread.h>
73 #include <private/qthread_p.h>
74 
75 #if QT_CONFIG(qml_network)
76 #include "qqmlnetworkaccessmanagerfactory.h"
77 #include <QNetworkAccessManager>
78 #include <QtNetwork/qnetworkconfigmanager.h>
79 #endif
80 
81 #include <private/qobject_p.h>
82 #include <private/qmetaobject_p.h>
83 #if QT_CONFIG(qml_locale)
84 #include <private/qqmllocale_p.h>
85 #endif
86 #include <private/qqmlbind_p.h>
87 #include <private/qqmlconnections_p.h>
88 #if QT_CONFIG(qml_animation)
89 #include <private/qqmltimer_p.h>
90 #endif
91 #include <private/qqmlplatform_p.h>
92 #include <private/qqmlloggingcategory_p.h>
93 
94 #ifdef Q_OS_WIN // for %APPDATA%
95 #  include <qt_windows.h>
96 #  ifndef Q_OS_WINRT
97 #    include <shlobj.h>
98 #  endif
99 #  include <qlibrary.h>
100 #  ifndef CSIDL_APPDATA
101 #    define CSIDL_APPDATA           0x001a  // <username>\Application Data
102 #  endif
103 #endif // Q_OS_WIN
104 
105 QT_BEGIN_NAMESPACE
106 
107 // Declared in qqml.h
qmlRegisterUncreatableMetaObject(const QMetaObject & staticMetaObject,const char * uri,int versionMajor,int versionMinor,const char * qmlName,const QString & reason)108 int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
109                                      const char *uri, int versionMajor,
110                                      int versionMinor, const char *qmlName,
111                                      const QString& reason)
112 {
113     QQmlPrivate::RegisterType type = {
114         0,
115 
116         0,
117         0,
118         0,
119         nullptr,
120         reason,
121 
122         uri, versionMajor, versionMinor, qmlName, &staticMetaObject,
123 
124         QQmlAttachedPropertiesFunc(),
125         nullptr,
126 
127         0,
128         0,
129         0,
130 
131         nullptr, nullptr,
132 
133         nullptr,
134         0
135     };
136 
137     return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
138 }
139 
140 /*!
141   \qmltype QtObject
142     \instantiates QObject
143   \inqmlmodule QtQml
144   \ingroup qml-utility-elements
145   \brief A basic QML type.
146 
147   The QtObject type is a non-visual element which contains only the
148   objectName property.
149 
150   It can be useful to create a QtObject if you need an extremely
151   lightweight type to enclose a set of custom properties:
152 
153   \snippet qml/qtobject.qml 0
154 
155   It can also be useful for C++ integration, as it is just a plain
156   QObject. See the QObject documentation for further details.
157 */
158 /*!
159   \qmlproperty string QtObject::objectName
160   This property holds the QObject::objectName for this specific object instance.
161 
162   This allows a C++ application to locate an item within a QML component
163   using the QObject::findChild() method. For example, the following C++
164   application locates the child \l Rectangle item and dynamically changes its
165   \c color value:
166 
167     \qml
168     // MyRect.qml
169 
170     import QtQuick 2.0
171 
172     Item {
173         width: 200; height: 200
174 
175         Rectangle {
176             anchors.fill: parent
177             color: "red"
178             objectName: "myRect"
179         }
180     }
181     \endqml
182 
183     \code
184     // main.cpp
185 
186     QQuickView view;
187     view.setSource(QUrl::fromLocalFile("MyRect.qml"));
188     view.show();
189 
190     QQuickItem *item = view.rootObject()->findChild<QQuickItem*>("myRect");
191     if (item)
192         item->setProperty("color", QColor(Qt::yellow));
193     \endcode
194 */
195 
196 bool QQmlEnginePrivate::qml_debugging_enabled = false;
197 bool QQmlEnginePrivate::s_designerMode = false;
198 
199 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
registerQuickTypes()200 void QQmlEnginePrivate::registerQuickTypes()
201 {
202     // Don't add anything here. These are only for backwards compatibility.
203     // Also, don't use qmlRegisterTypesAndRevisions as that will auto-add future revisions.
204 
205     const char uri[] = "QtQuick";
206 
207     qmlRegisterType<QQmlComponent>(uri, 2, 0, "Component");
208     qmlRegisterType<QObject>(uri, 2, 0, "QtObject");
209     qmlRegisterType<QQmlBind>(uri, 2, 0, "Binding");
210     qmlRegisterType<QQmlBind, 8>(uri, 2, 8, "Binding");
211     qmlRegisterCustomType<QQmlConnections>(uri, 2, 0, "Connections", new QQmlConnectionsParser);
212 
213     // Connections revision 3 was added in QtQml 2.3, but only in QtQuick 2.7.
214     qmlRegisterCustomType<QQmlConnections, 3>(uri, 2, 7, "Connections", new QQmlConnectionsParser);
215 
216 #if QT_CONFIG(qml_animation)
217     qmlRegisterType<QQmlTimer>(uri, 2, 0,"Timer");
218 #endif
219     qmlRegisterType<QQmlLoggingCategory>(uri, 2, 8, "LoggingCategory");
220     qmlRegisterType<QQmlLoggingCategory, 12>(uri, 2, 12, "LoggingCategory");
221 #if QT_CONFIG(qml_locale)
222     // Locale was added in QtQuick 2.0 and in QtQml 2.2
223     qmlRegisterUncreatableType<QQmlLocale>(uri, 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
224 #endif
225 }
226 #endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
227 
designerMode()228 bool QQmlEnginePrivate::designerMode()
229 {
230     return s_designerMode;
231 }
232 
activateDesignerMode()233 void QQmlEnginePrivate::activateDesignerMode()
234 {
235     s_designerMode = true;
236 }
237 
238 
239 /*!
240     \class QQmlImageProviderBase
241     \brief The QQmlImageProviderBase class is used to register image providers in the QML engine.
242     \inmodule QtQml
243 
244     Image providers must be registered with the QML engine.  The only information the QML
245     engine knows about image providers is the type of image data they provide.  To use an
246     image provider to acquire image data, you must cast the QQmlImageProviderBase pointer
247     to a QQuickImageProvider pointer.
248 
249     \sa QQuickImageProvider, QQuickTextureFactory
250 */
251 
252 /*!
253     \enum QQmlImageProviderBase::ImageType
254 
255     Defines the type of image supported by this image provider.
256 
257     \value Image The Image Provider provides QImage images.
258         The QQuickImageProvider::requestImage() method will be called for all image requests.
259     \value Pixmap The Image Provider provides QPixmap images.
260         The QQuickImageProvider::requestPixmap() method will be called for all image requests.
261     \value Texture The Image Provider provides QSGTextureProvider based images.
262         The QQuickImageProvider::requestTexture() method will be called for all image requests.
263     \value ImageResponse The Image provider provides QQuickTextureFactory based images.
264         Should only be used in QQuickAsyncImageProvider or its subclasses.
265         The QQuickAsyncImageProvider::requestImageResponse() method will be called for all image requests.
266         Since Qt 5.6
267     \omitvalue Invalid
268 */
269 
270 /*!
271     \enum QQmlImageProviderBase::Flag
272 
273     Defines specific requirements or features of this image provider.
274 
275     \value ForceAsynchronousImageLoading Ensures that image requests to the provider are
276         run in a separate thread, which allows the provider to spend as much time as needed
277         on producing the image without blocking the main thread.
278 */
279 
280 /*!
281     \fn QQmlImageProviderBase::imageType() const
282 
283     Implement this method to return the image type supported by this image provider.
284 */
285 
286 /*!
287     \fn QQmlImageProviderBase::flags() const
288 
289     Implement this to return the properties of this image provider.
290 */
291 
292 /*! \internal */
QQmlImageProviderBase()293 QQmlImageProviderBase::QQmlImageProviderBase()
294 {
295 }
296 
297 /*! \internal */
~QQmlImageProviderBase()298 QQmlImageProviderBase::~QQmlImageProviderBase()
299 {
300 }
301 
302 
303 /*!
304 \qmltype Qt
305 \inqmlmodule QtQml
306 \instantiates QQmlEnginePrivate
307 \ingroup qml-utility-elements
308 \keyword QmlGlobalQtObject
309 \brief Provides a global object with useful enums and functions from Qt.
310 
311 The \c Qt object is a global object with utility functions, properties and enums.
312 
313 It is not instantiable; to use it, call the members of the global \c Qt object directly.
314 For example:
315 
316 \qml
317 import QtQuick 2.0
318 
319 Text {
320     color: Qt.rgba(1, 0, 0, 1)
321     text: Qt.md5("hello, world")
322 }
323 \endqml
324 
325 
326 \section1 Enums
327 
328 The Qt object contains the enums available in the \l [QtCore]{Qt}{Qt Namespace}. For example, you can access
329 the \l Qt::LeftButton and \l Qt::RightButton enumeration values as \c Qt.LeftButton and \c Qt.RightButton.
330 
331 
332 \section1 Types
333 
334 The Qt object also contains helper functions for creating objects of specific
335 data types. This is primarily useful when setting the properties of an item
336 when the property has one of the following types:
337 \list
338 \li \c rect - use \l{Qt::rect()}{Qt.rect()}
339 \li \c point - use \l{Qt::point()}{Qt.point()}
340 \li \c size - use \l{Qt::size()}{Qt.size()}
341 \endlist
342 
343 If the \c QtQuick module has been imported, the following helper functions for
344 creating objects of specific data types are also available for clients to use:
345 \list
346 \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()}
347 \li \c font - use \l{Qt::font()}{Qt.font()}
348 \li \c vector2d - use \l{Qt::vector2d()}{Qt.vector2d()}
349 \li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
350 \li \c vector4d - use \l{Qt::vector4d()}{Qt.vector4d()}
351 \li \c quaternion - use \l{Qt::quaternion()}{Qt.quaternion()}
352 \li \c matrix4x4 - use \l{Qt::matrix4x4()}{Qt.matrix4x4()}
353 \endlist
354 
355 There are also string based constructors for these types. See \l{qtqml-typesystem-basictypes.html}{QML Basic Types} for more information.
356 
357 \section1 Date/Time Formatters
358 
359 The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
360 
361 \list
362     \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
363     \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
364     \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
365 \endlist
366 
367 The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
368 
369 
370 \section1 Dynamic Object Creation
371 The following functions on the global object allow you to dynamically create QML
372 items from files or strings. See \l{Dynamic QML Object Creation from JavaScript} for an overview
373 of their use.
374 
375 \list
376     \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
377     \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
378 \endlist
379 
380 
381 \section1 Other Functions
382 
383 The following functions are also on the Qt object.
384 
385 \list
386     \li \l{Qt::quit()}{Qt.quit()}
387     \li \l{Qt::md5()}{Qt.md5(string)}
388     \li \l{Qt::btoa()}{string Qt.btoa(string)}
389     \li \l{Qt::atob()}{string Qt.atob(string)}
390     \li \l{Qt::binding()}{object Qt.binding(function)}
391     \li \l{Qt::locale()}{object Qt.locale()}
392     \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
393     \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
394     \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
395 \endlist
396 */
397 
398 /*!
399     \qmlproperty object Qt::platform
400     \since 5.1
401 
402     The \c platform object provides info about the underlying platform.
403 
404     Its properties are:
405 
406     \table
407     \row
408     \li \c platform.os
409     \li
410 
411     This read-only property contains the name of the operating system.
412 
413     Possible values are:
414 
415     \list
416         \li \c "android" - Android
417         \li \c "ios" - iOS
418         \li \c "tvos" - tvOS
419         \li \c "linux" - Linux
420         \li \c "osx" - \macos
421         \li \c "qnx" - QNX (since Qt 5.9.3)
422         \li \c "unix" - Other Unix-based OS
423         \li \c "windows" - Windows
424         \li \c "winrt" - WinRT / UWP
425         \li \c "wasm" - WebAssembly
426     \endlist
427 
428     \row
429     \li \c platform.pluginName
430     \li This is the name of the platform set on the QGuiApplication instance
431         as returned by \l QGuiApplication::platformName()
432 
433     \endtable
434 */
435 
436 /*!
437     \qmlproperty object Qt::application
438     \since 5.1
439 
440     The \c application object provides access to global application state
441     properties shared by many QML components.
442 
443     Its properties are:
444 
445     \table
446     \row
447     \li \c application.active
448     \li
449     Deprecated, use Qt.application.state == Qt.ApplicationActive instead.
450 
451     \row
452     \li \c application.state
453     \li
454     This read-only property indicates the current state of the application.
455 
456     Possible values are:
457 
458     \list
459     \li Qt.ApplicationActive - The application is the top-most and focused application, and the
460                                user is able to interact with the application.
461     \li Qt.ApplicationInactive - The application is visible or partially visible, but not selected
462                                  to be in front, the user cannot interact with the application.
463                                  On desktop platforms, this typically means that the user activated
464                                  another application. On mobile platforms, it is more common to
465                                  enter this state when the OS is interrupting the user with for
466                                  example incoming calls, SMS-messages or dialogs. This is usually a
467                                  transient state during which the application is paused. The user
468                                  may return focus to your application, but most of the time it will
469                                  be the first indication that the application is going to be suspended.
470                                  While in this state, consider pausing or stopping any activity that
471                                  should not continue when the user cannot interact with your
472                                  application, such as a video, a game, animations, or sensors.
473                                  You should also avoid performing CPU-intensive tasks which might
474                                  slow down the application in front.
475     \li Qt.ApplicationSuspended - The application is suspended and not visible to the user. On
476                                   mobile platforms, the application typically enters this state when
477                                   the user returns to the home screen or switches to another
478                                   application. While in this state, the application should ensure
479                                   that the user perceives it as always alive and does not lose his
480                                   progress, saving any persistent data. The application should cease
481                                   all activities and be prepared for code execution to stop. While
482                                   suspended, the application can be killed at any time without
483                                   further warnings (for example when low memory forces the OS to purge
484                                   suspended applications).
485     \li Qt.ApplicationHidden - The application is hidden and runs in the background. This is the
486                                normal state for applications that need to do background processing,
487                                like playing music, while the user interacts with other applications.
488                                The application should free up all graphical resources when entering
489                                this state. A Qt Quick application should not usually handle this state
490                                at the QML level. Instead, you should unload the entire UI and reload
491                                the QML files whenever the application becomes active again.
492     \endlist
493 
494     \row
495     \li \c application.layoutDirection
496     \li
497     This read-only property can be used to query the default layout direction of the
498     application. On system start-up, the default layout direction depends on the
499     application's language. The property has a value of \c Qt.RightToLeft in locales
500     where text and graphic elements are read from right to left, and \c Qt.LeftToRight
501     where the reading direction flows from left to right. You can bind to this
502     property to customize your application layouts to support both layout directions.
503 
504     Possible values are:
505 
506     \list
507     \li Qt.LeftToRight - Text and graphics elements should be positioned
508                         from left to right.
509     \li Qt.RightToLeft - Text and graphics elements should be positioned
510                         from right to left.
511     \endlist
512     \row
513     \li \c application.font
514     \li This read-only property holds the default application font as
515         returned by \l QGuiApplication::font().
516     \row
517     \li \c application.arguments
518     \li This is a string list of the arguments the executable was invoked with.
519     \row
520     \li \c application.name
521     \li This is the application name set on the QCoreApplication instance. This property can be written
522     to in order to set the application name.
523     \row
524     \li \c application.displayName (since Qt 5.9)
525     \li This is the application display name set on the QGuiApplication instance. This property can be written
526     to in order to set the application display name.
527     \row
528     \li \c application.version
529     \li This is the application version set on the QCoreApplication instance. This property can be written
530     to in order to set the application version.
531     \row
532     \li \c application.organization
533     \li This is the organization name set on the QCoreApplication instance. This property can be written
534     to in order to set the organization name.
535     \row
536     \li \c application.domain
537     \li This is the organization domain set on the QCoreApplication instance. This property can be written
538     to in order to set the organization domain.
539 
540     \row
541     \li \c application.supportsMultipleWindows
542     \li This read-only property can be used to determine whether or not the
543         platform supports multiple windows. Some embedded platforms do not support
544         multiple windows, for example.
545 
546     \row
547     \li \c application.screens
548     \li An array containing the descriptions of all connected screens. The
549     elements of the array are objects with the same properties as the
550     \l{Screen} attached object. In practice the array corresponds to the screen
551     list returned by QGuiApplication::screens(). In addition to examining
552     properties like name, width, height, etc., the array elements can also be
553     assigned to the screen property of Window items, thus serving as an
554     alternative to the C++ side's QWindow::setScreen(). This property has been
555     added in Qt 5.9.
556 
557     \endtable
558 
559     The object also has one signal, aboutToQuit(), which is the same as \l QCoreApplication::aboutToQuit().
560 
561     The following example uses the \c application object to indicate
562     whether the application is currently active:
563 
564     \snippet qml/application.qml document
565 
566     Note that when using QML without a QGuiApplication, the following properties will be undefined:
567     \list
568     \li application.active
569     \li application.state
570     \li application.layoutDirection
571     \li application.font
572     \endlist
573 
574     \sa Screen, Window, {QtQuick.Window::Window::screen}{Window.screen}
575 */
576 
577 /*!
578     \qmlproperty object Qt::inputMethod
579     \since 5.0
580 
581     The \c inputMethod object allows access to application's QInputMethod object
582     and all its properties and slots. See the QInputMethod documentation for
583     further details.
584 */
585 
586 /*!
587     \qmlproperty object Qt::styleHints
588     \since 5.5
589 
590     The \c styleHints object provides platform-specific style hints and settings.
591     See the QStyleHints documentation for further details.
592 
593     \note The \c styleHints object is only available when using the Qt Quick module.
594 
595     The following example uses the \c styleHints object to determine whether an
596     item should gain focus on mouse press or touch release:
597     \code
598     import QtQuick 2.4
599 
600     MouseArea {
601         id: button
602 
603         onPressed: {
604             if (!Qt.styleHints.setFocusOnTouchRelease)
605                 button.forceActiveFocus()
606         }
607         onReleased: {
608             if (Qt.styleHints.setFocusOnTouchRelease)
609                 button.forceActiveFocus()
610         }
611     }
612     \endcode
613 */
614 
615 /*!
616 \qmlmethod object Qt::include(string url, jsobject callback)
617 \deprecated
618 
619 This method should not be used. Use ECMAScript modules instead and the native
620 JavaScript \c import and \c export statements instead.
621 
622 Includes another JavaScript file. This method can only be used from within JavaScript files,
623 and not regular QML files.
624 
625 This imports all functions from \a url into the current script's namespace.
626 
627 Qt.include() returns an object that describes the status of the operation.  The object has
628 a single property, \c {status}, that is set to one of the following values:
629 
630 \table
631 \header \li Symbol \li Value \li Description
632 \row \li result.OK \li 0 \li The include completed successfully.
633 \row \li result.LOADING \li 1 \li Data is being loaded from the network.
634 \row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
635 \row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
636 An additional \c exception property will be set in this case.
637 \endtable
638 
639 The \c status property will be updated as the operation progresses.
640 
641 If provided, \a callback is invoked when the operation completes.  The callback is passed
642 the same object as is returned from the Qt.include() call.
643 */
644 // Qt.include() is implemented in qv4include.cpp
645 
QQmlEnginePrivate(QQmlEngine * e)646 QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
647 : propertyCapture(nullptr), rootContext(nullptr),
648 #if QT_CONFIG(qml_debug)
649   profiler(nullptr),
650 #endif
651   outputWarningsToMsgLog(true),
652   cleanup(nullptr), erroredBindings(nullptr), inProgressCreations(0),
653 #if QT_CONFIG(qml_worker_script)
654   workerScriptEngine(nullptr),
655 #endif
656   activeObjectCreator(nullptr),
657 #if QT_CONFIG(qml_network)
658   networkAccessManager(nullptr), networkAccessManagerFactory(nullptr),
659 #endif
660   urlInterceptor(nullptr), scarceResourcesRefCount(0), importDatabase(e), typeLoader(e),
661   uniqueId(1), incubatorCount(0), incubationController(nullptr)
662 {
663 }
664 
~QQmlEnginePrivate()665 QQmlEnginePrivate::~QQmlEnginePrivate()
666 {
667     if (inProgressCreations)
668         qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
669 
670     while (cleanup) {
671         QQmlCleanup *c = cleanup;
672         cleanup = c->next;
673         if (cleanup) cleanup->prev = &cleanup;
674         c->next = nullptr;
675         c->prev = nullptr;
676         c->clear();
677     }
678 
679     doDeleteInEngineThread();
680 
681     if (incubationController) incubationController->d = nullptr;
682     incubationController = nullptr;
683 
684     QQmlMetaType::freeUnusedTypesAndCaches();
685 
686     for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) {
687         iter.value()->isRegisteredWithEngine = false;
688         QQmlMetaType::unregisterInternalCompositeType({iter.value()->metaTypeId, iter.value()->listMetaTypeId});
689     }
690 #if QT_CONFIG(qml_debug)
691     delete profiler;
692 #endif
693 }
694 
qdeclarativeelement_destructor(QObject * o)695 void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
696 {
697     if (QQmlData *d = QQmlData::get(o)) {
698         if (d->ownContext) {
699             for (QQmlContextData *lc = d->ownContext->linkedContext; lc; lc = lc->linkedContext) {
700                 lc->invalidate();
701                 if (lc->contextObject == o)
702                     lc->contextObject = nullptr;
703             }
704             d->ownContext->invalidate();
705             if (d->ownContext->contextObject == o)
706                 d->ownContext->contextObject = nullptr;
707             d->ownContext = nullptr;
708             d->context = nullptr;
709         }
710 
711         if (d->outerContext && d->outerContext->contextObject == o)
712             d->outerContext->contextObject = nullptr;
713 
714         // Mark this object as in the process of deletion to
715         // prevent it resolving in bindings
716         QQmlData::markAsDeleted(o);
717 
718         // Disconnect the notifiers now - during object destruction this would be too late, since
719         // the disconnect call wouldn't be able to call disconnectNotify(), as it isn't possible to
720         // get the metaobject anymore.
721         d->disconnectNotifiers();
722     }
723 }
724 
QQmlData()725 QQmlData::QQmlData()
726     : ownedByQml1(false), ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
727       hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
728       hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
729       bindingBitsArraySize(InlineBindingArraySize), notifyList(nullptr),
730       bindings(nullptr), signalHandlers(nullptr), nextContextObject(nullptr), prevContextObject(nullptr),
731       lineNumber(0), columnNumber(0), jsEngineId(0),
732       propertyCache(nullptr), guards(nullptr), extendedData(nullptr)
733 {
734     memset(bindingBitsValue, 0, sizeof(bindingBitsValue));
735     init();
736 }
737 
~QQmlData()738 QQmlData::~QQmlData()
739 {
740 }
741 
destroyed(QAbstractDeclarativeData * d,QObject * o)742 void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
743 {
744     QQmlData *ddata = static_cast<QQmlData *>(d);
745     if (ddata->ownedByQml1)
746         return;
747     ddata->destroyed(o);
748 }
749 
parentChanged(QAbstractDeclarativeData * d,QObject * o,QObject * p)750 void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
751 {
752     QQmlData *ddata = static_cast<QQmlData *>(d);
753     if (ddata->ownedByQml1)
754         return;
755     ddata->parentChanged(o, p);
756 }
757 
758 class QQmlThreadNotifierProxyObject : public QObject
759 {
760 public:
761     QPointer<QObject> target;
762 
qt_metacall(QMetaObject::Call,int methodIndex,void ** a)763     int qt_metacall(QMetaObject::Call, int methodIndex, void **a) override {
764         if (!target)
765             return -1;
766 
767         QMetaMethod method = target->metaObject()->method(methodIndex);
768         Q_ASSERT(method.methodType() == QMetaMethod::Signal);
769         int signalIndex = QMetaObjectPrivate::signalIndex(method);
770         QQmlData *ddata = QQmlData::get(target, false);
771         QQmlNotifierEndpoint *ep = ddata->notify(signalIndex);
772         if (ep) QQmlNotifier::emitNotify(ep, a);
773 
774         delete this;
775 
776         return -1;
777     }
778 };
779 
signalEmitted(QAbstractDeclarativeData *,QObject * object,int index,void ** a)780 void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int index, void **a)
781 {
782     QQmlData *ddata = QQmlData::get(object, false);
783     if (!ddata) return; // Probably being deleted
784     if (ddata->ownedByQml1) return;
785 
786     // In general, QML only supports QObject's that live on the same thread as the QQmlEngine
787     // that they're exposed to.  However, to make writing "worker objects" that calculate data
788     // in a separate thread easier, QML allows a QObject that lives in the same thread as the
789     // QQmlEngine to emit signals from a different thread.  These signals are then automatically
790     // marshalled back onto the QObject's thread and handled by QML from there.  This is tested
791     // by the qqmlecmascript::threadSignal() autotest.
792     if (!ddata->notifyList)
793         return;
794 
795     auto objectThreadData = QObjectPrivate::get(object)->threadData.loadRelaxed();
796     if (QThread::currentThreadId() != objectThreadData->threadId.loadRelaxed()) {
797         if (!objectThreadData->thread.loadAcquire())
798             return;
799 
800         QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
801         QList<QByteArray> parameterTypes = m.parameterTypes();
802 
803         QScopedPointer<QMetaCallEvent> ev(new QMetaCallEvent(m.methodIndex(), 0, nullptr,
804                                                              object, index,
805                                                              parameterTypes.count() + 1));
806 
807         void **args = ev->args();
808         int *types = ev->types();
809 
810         for (int ii = 0; ii < parameterTypes.count(); ++ii) {
811             const QByteArray &typeName = parameterTypes.at(ii);
812             if (typeName.endsWith('*'))
813                 types[ii + 1] = QMetaType::VoidStar;
814             else
815                 types[ii + 1] = QMetaType::type(typeName);
816 
817             if (!types[ii + 1]) {
818                 qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
819                          "(Make sure '%s' is registered using qRegisterMetaType().)",
820                          typeName.constData(), typeName.constData());
821                 return;
822             }
823 
824             args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
825         }
826 
827         QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
828         mpo->target = object;
829         mpo->moveToThread(objectThreadData->thread.loadAcquire());
830         QCoreApplication::postEvent(mpo, ev.take());
831 
832     } else {
833         QQmlNotifierEndpoint *ep = ddata->notify(index);
834         if (ep) QQmlNotifier::emitNotify(ep, a);
835     }
836 }
837 
receivers(QAbstractDeclarativeData * d,const QObject *,int index)838 int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
839 {
840     QQmlData *ddata = static_cast<QQmlData *>(d);
841     if (ddata->ownedByQml1)
842         return 0;
843     return ddata->endpointCount(index);
844 }
845 
isSignalConnected(QAbstractDeclarativeData * d,const QObject *,int index)846 bool QQmlData::isSignalConnected(QAbstractDeclarativeData *d, const QObject *, int index)
847 {
848     QQmlData *ddata = static_cast<QQmlData *>(d);
849     if (ddata->ownedByQml1)
850         return false;
851     return ddata->signalHasEndpoint(index);
852 }
853 
endpointCount(int index)854 int QQmlData::endpointCount(int index)
855 {
856     int count = 0;
857     QQmlNotifierEndpoint *ep = notify(index);
858     if (!ep)
859         return count;
860     ++count;
861     while (ep->next) {
862         ++count;
863         ep = ep->next;
864     }
865     return count;
866 }
867 
markAsDeleted(QObject * o)868 void QQmlData::markAsDeleted(QObject *o)
869 {
870     QQmlData::setQueuedForDeletion(o);
871 
872     QObjectPrivate *p = QObjectPrivate::get(o);
873     for (QList<QObject *>::const_iterator it = p->children.constBegin(), end = p->children.constEnd(); it != end; ++it) {
874         QQmlData::markAsDeleted(*it);
875     }
876 }
877 
setQueuedForDeletion(QObject * object)878 void QQmlData::setQueuedForDeletion(QObject *object)
879 {
880     if (object) {
881         if (QQmlData *ddata = QQmlData::get(object)) {
882             if (ddata->ownContext) {
883                 Q_ASSERT(ddata->ownContext == ddata->context);
884                 ddata->context->emitDestruction();
885                 if (ddata->ownContext->contextObject == object)
886                     ddata->ownContext->contextObject = nullptr;
887                 ddata->ownContext = nullptr;
888                 ddata->context = nullptr;
889             }
890             ddata->isQueuedForDeletion = true;
891         }
892     }
893 }
894 
flushPendingBindingImpl(QQmlPropertyIndex index)895 void QQmlData::flushPendingBindingImpl(QQmlPropertyIndex index)
896 {
897     clearPendingBindingBit(index.coreIndex());
898 
899     // Find the binding
900     QQmlAbstractBinding *b = bindings;
901     while (b && (b->targetPropertyIndex().coreIndex() != index.coreIndex() ||
902                  b->targetPropertyIndex().hasValueTypeIndex()))
903         b = b->nextBinding();
904 
905     if (b && b->targetPropertyIndex().coreIndex() == index.coreIndex() &&
906             !b->targetPropertyIndex().hasValueTypeIndex())
907         b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
908                             QQmlPropertyData::DontRemoveBinding);
909 }
910 
DeferredData()911 QQmlData::DeferredData::DeferredData()
912 {
913 }
914 
~DeferredData()915 QQmlData::DeferredData::~DeferredData()
916 {
917 }
918 
919 bool QQmlEnginePrivate::baseModulesUninitialized = true;
init()920 void QQmlEnginePrivate::init()
921 {
922     Q_Q(QQmlEngine);
923 
924     if (baseModulesUninitialized) {
925 
926         // required for the Compiler.
927         qmlRegisterType<QObject>("QML", 1, 0, "QtObject");
928         qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component");
929 
930         QQmlData::init();
931         baseModulesUninitialized = false;
932     }
933 
934     qRegisterMetaType<QVariant>();
935     qRegisterMetaType<QQmlScriptString>();
936     qRegisterMetaType<QJSValue>();
937     qRegisterMetaType<QQmlComponent::Status>();
938     qRegisterMetaType<QList<QObject*> >();
939     qRegisterMetaType<QList<int> >();
940     qRegisterMetaType<QQmlBinding*>();
941 
942     q->handle()->setQmlEngine(q);
943 
944     rootContext = new QQmlContext(q,true);
945 }
946 
947 /*!
948   \class QQmlEngine
949   \since 5.0
950   \inmodule QtQml
951   \brief The QQmlEngine class provides an environment for instantiating QML components.
952 
953   Each QML component is instantiated in a QQmlContext.
954   QQmlContext's are essential for passing data to QML
955   components.  In QML, contexts are arranged hierarchically and this
956   hierarchy is managed by the QQmlEngine.
957 
958   Prior to creating any QML components, an application must have
959   created a QQmlEngine to gain access to a QML context.  The
960   following example shows how to create a simple Text item.
961 
962   \code
963   QQmlEngine engine;
964   QQmlComponent component(&engine);
965   component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
966   QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
967 
968   //add item to view, etc
969   ...
970   \endcode
971 
972   In this case, the Text item will be created in the engine's
973   \l {QQmlEngine::rootContext()}{root context}.
974 
975   \sa QQmlComponent, QQmlContext, {QML Global Object}
976 */
977 
978 /*!
979   Create a new QQmlEngine with the given \a parent.
980 */
QQmlEngine(QObject * parent)981 QQmlEngine::QQmlEngine(QObject *parent)
982 : QJSEngine(*new QQmlEnginePrivate(this), parent)
983 {
984     Q_D(QQmlEngine);
985     d->init();
986     QJSEnginePrivate::addToDebugServer(this);
987 }
988 
989 /*!
990 * \internal
991 */
QQmlEngine(QQmlEnginePrivate & dd,QObject * parent)992 QQmlEngine::QQmlEngine(QQmlEnginePrivate &dd, QObject *parent)
993 : QJSEngine(dd, parent)
994 {
995     Q_D(QQmlEngine);
996     d->init();
997 }
998 
999 /*!
1000   Destroys the QQmlEngine.
1001 
1002   Any QQmlContext's created on this engine will be
1003   invalidated, but not destroyed (unless they are parented to the
1004   QQmlEngine object).
1005 
1006   See QJSEngine docs for details on cleaning up the JS engine.
1007 */
~QQmlEngine()1008 QQmlEngine::~QQmlEngine()
1009 {
1010     Q_D(QQmlEngine);
1011     QJSEnginePrivate::removeFromDebugServer(this);
1012 
1013     // Emit onDestruction signals for the root context before
1014     // we destroy the contexts, engine, Singleton Types etc. that
1015     // may be required to handle the destruction signal.
1016     QQmlContextData::get(rootContext())->emitDestruction();
1017 
1018     // clean up all singleton type instances which we own.
1019     // we do this here and not in the private dtor since otherwise a crash can
1020     // occur (if we are the QObject parent of the QObject singleton instance)
1021     // XXX TODO: performance -- store list of singleton types separately?
1022     const QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
1023     for (const QQmlType &currType : singletonTypes)
1024         d->destroySingletonInstance(currType);
1025 
1026     delete d->rootContext;
1027     d->rootContext = nullptr;
1028 
1029     d->typeLoader.invalidate();
1030 }
1031 
1032 /*! \fn void QQmlEngine::quit()
1033     This signal is emitted when the QML loaded by the engine would like to quit.
1034 
1035     \sa exit()
1036  */
1037 
1038 /*! \fn void QQmlEngine::exit(int retCode)
1039     This signal is emitted when the QML loaded by the engine would like to exit
1040     from the event loop with the specified return code \a retCode.
1041 
1042     \since 5.8
1043     \sa quit()
1044  */
1045 
1046 
1047 /*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
1048     This signal is emitted when \a warnings messages are generated by QML.
1049  */
1050 
1051 /*!
1052   Clears the engine's internal component cache.
1053 
1054   This function causes the property metadata of all components previously
1055   loaded by the engine to be destroyed.  All previously loaded components and
1056   the property bindings for all extant objects created from those components will
1057   cease to function.
1058 
1059   This function returns the engine to a state where it does not contain any loaded
1060   component data.  This may be useful in order to reload a smaller subset of the
1061   previous component set, or to load a new version of a previously loaded component.
1062 
1063   Once the component cache has been cleared, components must be loaded before
1064   any new objects can be created.
1065 
1066   \sa trimComponentCache()
1067  */
clearComponentCache()1068 void QQmlEngine::clearComponentCache()
1069 {
1070     Q_D(QQmlEngine);
1071     d->typeLoader.lock();
1072     d->typeLoader.clearCache();
1073     d->typeLoader.unlock();
1074 }
1075 
1076 /*!
1077   Trims the engine's internal component cache.
1078 
1079   This function causes the property metadata of any loaded components which are
1080   not currently in use to be destroyed.
1081 
1082   A component is considered to be in use if there are any extant instances of
1083   the component itself, any instances of other components that use the component,
1084   or any objects instantiated by any of those components.
1085 
1086   \sa clearComponentCache()
1087  */
trimComponentCache()1088 void QQmlEngine::trimComponentCache()
1089 {
1090     Q_D(QQmlEngine);
1091     d->typeLoader.trimCache();
1092 }
1093 
1094 /*!
1095   Returns the engine's root context.
1096 
1097   The root context is automatically created by the QQmlEngine.
1098   Data that should be available to all QML component instances
1099   instantiated by the engine should be put in the root context.
1100 
1101   Additional data that should only be available to a subset of
1102   component instances should be added to sub-contexts parented to the
1103   root context.
1104 */
rootContext() const1105 QQmlContext *QQmlEngine::rootContext() const
1106 {
1107     Q_D(const QQmlEngine);
1108     return d->rootContext;
1109 }
1110 
1111 /*!
1112   \internal
1113   This API is private for 5.1
1114 
1115   Sets the \a urlInterceptor to be used when resolving URLs in QML.
1116   This also applies to URLs used for loading script files and QML types.
1117   This should not be modifed while the engine is loading files, or URL
1118   selection may be inconsistent.
1119 */
setUrlInterceptor(QQmlAbstractUrlInterceptor * urlInterceptor)1120 void QQmlEngine::setUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
1121 {
1122     Q_D(QQmlEngine);
1123     d->urlInterceptor = urlInterceptor;
1124 }
1125 
1126 /*!
1127   \internal
1128   This API is private for 5.1
1129 
1130   Returns the current QQmlAbstractUrlInterceptor. It must not be modified outside
1131   the GUI thread.
1132 */
urlInterceptor() const1133 QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const
1134 {
1135     Q_D(const QQmlEngine);
1136     return d->urlInterceptor;
1137 }
1138 
registerFinalizeCallback(QObject * obj,int index)1139 void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
1140 {
1141     if (activeObjectCreator) {
1142         activeObjectCreator->finalizeCallbacks()->append(qMakePair(QPointer<QObject>(obj), index));
1143     } else {
1144         void *args[] = { nullptr };
1145         QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
1146     }
1147 }
1148 
imageProvider(const QString & providerId) const1149 QSharedPointer<QQmlImageProviderBase> QQmlEnginePrivate::imageProvider(const QString &providerId) const
1150 {
1151     const QString providerIdLower = providerId.toLower();
1152     QMutexLocker locker(&mutex);
1153     return imageProviders.value(providerIdLower);
1154 }
1155 
1156 #if QT_CONFIG(qml_network)
1157 /*!
1158   Sets the \a factory to use for creating QNetworkAccessManager(s).
1159 
1160   QNetworkAccessManager is used for all network access by QML.  By
1161   implementing a factory it is possible to create custom
1162   QNetworkAccessManager with specialized caching, proxy and cookie
1163   support.
1164 
1165   The factory must be set before executing the engine.
1166 
1167   \note QQmlEngine does not take ownership of the factory.
1168 */
setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory * factory)1169 void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
1170 {
1171     Q_D(QQmlEngine);
1172     QMutexLocker locker(&d->networkAccessManagerMutex);
1173     d->networkAccessManagerFactory = factory;
1174 }
1175 
1176 /*!
1177   Returns the current QQmlNetworkAccessManagerFactory.
1178 
1179   \sa setNetworkAccessManagerFactory()
1180 */
networkAccessManagerFactory() const1181 QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
1182 {
1183     Q_D(const QQmlEngine);
1184     return d->networkAccessManagerFactory;
1185 }
1186 
createNetworkAccessManager(QObject * parent) const1187 QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
1188 {
1189     QMutexLocker locker(&networkAccessManagerMutex);
1190     QNetworkAccessManager *nam;
1191     if (networkAccessManagerFactory) {
1192         nam = networkAccessManagerFactory->create(parent);
1193     } else {
1194         nam = new QNetworkAccessManager(parent);
1195     }
1196 
1197     return nam;
1198 }
1199 
getNetworkAccessManager() const1200 QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const
1201 {
1202     Q_Q(const QQmlEngine);
1203     if (!networkAccessManager)
1204         networkAccessManager = createNetworkAccessManager(const_cast<QQmlEngine*>(q));
1205     return networkAccessManager;
1206 }
1207 
1208 /*!
1209   Returns a common QNetworkAccessManager which can be used by any QML
1210   type instantiated by this engine.
1211 
1212   If a QQmlNetworkAccessManagerFactory has been set and a
1213   QNetworkAccessManager has not yet been created, the
1214   QQmlNetworkAccessManagerFactory will be used to create the
1215   QNetworkAccessManager; otherwise the returned QNetworkAccessManager
1216   will have no proxy or cache set.
1217 
1218   \sa setNetworkAccessManagerFactory()
1219 */
networkAccessManager() const1220 QNetworkAccessManager *QQmlEngine::networkAccessManager() const
1221 {
1222     Q_D(const QQmlEngine);
1223     return d->getNetworkAccessManager();
1224 }
1225 #endif // qml_network
1226 
1227 /*!
1228 
1229   Sets the \a provider to use for images requested via the \e
1230   image: url scheme, with host \a providerId. The QQmlEngine
1231   takes ownership of \a provider.
1232 
1233   Image providers enable support for pixmap and threaded image
1234   requests. See the QQuickImageProvider documentation for details on
1235   implementing and using image providers.
1236 
1237   All required image providers should be added to the engine before any
1238   QML sources files are loaded.
1239 
1240   \sa removeImageProvider(), QQuickImageProvider, QQmlImageProviderBase
1241 */
addImageProvider(const QString & providerId,QQmlImageProviderBase * provider)1242 void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
1243 {
1244     Q_D(QQmlEngine);
1245     QString providerIdLower = providerId.toLower();
1246     QSharedPointer<QQmlImageProviderBase> sp(provider);
1247     QMutexLocker locker(&d->mutex);
1248     d->imageProviders.insert(std::move(providerIdLower), std::move(sp));
1249 }
1250 
1251 /*!
1252   Returns the image provider set for \a providerId if found; otherwise returns \nullptr.
1253 
1254   \sa QQuickImageProvider
1255 */
imageProvider(const QString & providerId) const1256 QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
1257 {
1258     Q_D(const QQmlEngine);
1259     const QString providerIdLower = providerId.toLower();
1260     QMutexLocker locker(&d->mutex);
1261     return d->imageProviders.value(providerIdLower).data();
1262 }
1263 
1264 /*!
1265   Removes the image provider for \a providerId.
1266 
1267   \sa addImageProvider(), QQuickImageProvider
1268 */
removeImageProvider(const QString & providerId)1269 void QQmlEngine::removeImageProvider(const QString &providerId)
1270 {
1271     Q_D(QQmlEngine);
1272     const QString providerIdLower = providerId.toLower();
1273     QMutexLocker locker(&d->mutex);
1274     d->imageProviders.take(providerIdLower);
1275 }
1276 
1277 /*!
1278   Return the base URL for this engine.  The base URL is only used to
1279   resolve components when a relative URL is passed to the
1280   QQmlComponent constructor.
1281 
1282   If a base URL has not been explicitly set, this method returns the
1283   application's current working directory.
1284 
1285   \sa setBaseUrl()
1286 */
baseUrl() const1287 QUrl QQmlEngine::baseUrl() const
1288 {
1289     Q_D(const QQmlEngine);
1290     if (d->baseUrl.isEmpty()) {
1291         const QString currentPath = QDir::currentPath();
1292         const QString rootPath = QDir::rootPath();
1293         return QUrl::fromLocalFile((currentPath == rootPath) ? rootPath : (currentPath + QDir::separator()));
1294     } else {
1295         return d->baseUrl;
1296     }
1297 }
1298 
1299 /*!
1300   Set the  base URL for this engine to \a url.
1301 
1302   \sa baseUrl()
1303 */
setBaseUrl(const QUrl & url)1304 void QQmlEngine::setBaseUrl(const QUrl &url)
1305 {
1306     Q_D(QQmlEngine);
1307     d->baseUrl = url;
1308 }
1309 
1310 /*!
1311   Returns true if warning messages will be output to stderr in addition
1312   to being emitted by the warnings() signal, otherwise false.
1313 
1314   The default value is true.
1315 */
outputWarningsToStandardError() const1316 bool QQmlEngine::outputWarningsToStandardError() const
1317 {
1318     Q_D(const QQmlEngine);
1319     return d->outputWarningsToMsgLog;
1320 }
1321 
1322 /*!
1323   Set whether warning messages will be output to stderr to \a enabled.
1324 
1325   If \a enabled is true, any warning messages generated by QML will be
1326   output to stderr and emitted by the warnings() signal.  If \a enabled
1327   is false, only the warnings() signal will be emitted.  This allows
1328   applications to handle warning output themselves.
1329 
1330   The default value is true.
1331 */
setOutputWarningsToStandardError(bool enabled)1332 void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
1333 {
1334     Q_D(QQmlEngine);
1335     d->outputWarningsToMsgLog = enabled;
1336 }
1337 
1338 /*!
1339   \qmlproperty string Qt::uiLanguage
1340   \since 5.15
1341 
1342   The uiLanguage holds the name of the language to be used for user interface
1343   string translations. It is exposed in C++ as QQmlEngine::uiLanguage property.
1344 
1345   You can set the value freely and use it in bindings. It is recommended to set it
1346   after installing translators in your application. By convention, an empty string
1347   means no translation from the language used in the source code is intended to occur.
1348 
1349   If you're using QQmlApplicationEngine and the value changes, QQmlEngine::retranslate()
1350   will be called.
1351 */
1352 
1353 /*!
1354   \fn template<typename T> T QQmlEngine::singletonInstance(int qmlTypeId)
1355 
1356   Returns the instance of a singleton type that was registered under \a qmlTypeId.
1357 
1358   The template argument \e T may be either QJSValue or a pointer to a QObject-derived
1359   type and depends on how the singleton was registered. If no instance of \e T has been
1360   created yet, it is created now. If \a qmlTypeId does not represent a valid singleton
1361   type, either a default constructed QJSValue or a \c nullptr is returned.
1362 
1363   QObject* example:
1364   \code
1365   class MySingleton : public QObject {
1366     Q_OBJECT
1367 
1368     // Register as default constructed singleton.
1369     QML_ELEMENT
1370     QML_SINGLETON
1371 
1372     static int typeId;
1373     // ...
1374   };
1375 
1376   MySingleton::typeId = qmlTypeId(...);
1377 
1378   // Retrieve as QObject*
1379   QQmlEngine engine;
1380   MySingleton* instance = engine.singletonInstance<MySingleton*>(MySingleton::typeId);
1381   \endcode
1382 
1383   QJSValue example:
1384   \code
1385   // Register with QJSValue callback
1386   int typeId = qmlRegisterSingletonType(...);
1387 
1388   // Retrieve as QJSValue
1389   QQmlEngine engine;
1390   QJSValue instance = engine.singletonInstance<QJSValue>(typeId);
1391   \endcode
1392 
1393   It is recommended to store the QML type id, e.g. as a static member in the
1394   singleton class. The lookup via qmlTypeId() is costly.
1395 
1396   \sa QML_SINGLETON, qmlRegisterSingletonType(), qmlTypeId()
1397   \since 5.12
1398 */
1399 template<>
singletonInstance(int qmlTypeId)1400 QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
1401 {
1402     Q_D(QQmlEngine);
1403     QQmlType type = QQmlMetaType::qmlType(qmlTypeId, QQmlMetaType::TypeIdCategory::QmlType);
1404 
1405     if (!type.isValid() || !type.isSingleton())
1406         return QJSValue();
1407 
1408     return d->singletonInstance<QJSValue>(type);
1409 }
1410 
1411 /*!
1412   Refreshes all binding expressions that use strings marked for translation.
1413 
1414   Call this function after you have installed a new translator with
1415   QCoreApplication::installTranslator, to ensure that your user-interface
1416   shows up-to-date translations.
1417 
1418   \note Due to a limitation in the implementation, this function
1419   refreshes all the engine's bindings, not only those that use strings
1420   marked for translation.
1421   This may be optimized in a future release.
1422 
1423   \since 5.10
1424 */
retranslate()1425 void QQmlEngine::retranslate()
1426 {
1427     Q_D(QQmlEngine);
1428     QQmlContextData *context = QQmlContextData::get(d->rootContext)->childContexts;
1429     while (context) {
1430         context->refreshExpressions();
1431         context = context->nextChild;
1432     }
1433 }
1434 
1435 /*!
1436   Returns the QQmlContext for the \a object, or 0 if no
1437   context has been set.
1438 
1439   When the QQmlEngine instantiates a QObject, the context is
1440   set automatically.
1441 
1442   \sa qmlContext(), qmlEngine()
1443   */
contextForObject(const QObject * object)1444 QQmlContext *QQmlEngine::contextForObject(const QObject *object)
1445 {
1446     if(!object)
1447         return nullptr;
1448 
1449     QQmlData *data = QQmlData::get(object);
1450     if (data && data->outerContext)
1451         return data->outerContext->asQQmlContext();
1452 
1453     return nullptr;
1454 }
1455 
1456 /*!
1457   Sets the QQmlContext for the \a object to \a context.
1458   If the \a object already has a context, a warning is
1459   output, but the context is not changed.
1460 
1461   When the QQmlEngine instantiates a QObject, the context is
1462   set automatically.
1463  */
setContextForObject(QObject * object,QQmlContext * context)1464 void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
1465 {
1466     if (!object || !context)
1467         return;
1468 
1469     QQmlData *data = QQmlData::get(object, true);
1470     if (data->context) {
1471         qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext");
1472         return;
1473     }
1474 
1475     QQmlContextData *contextData = QQmlContextData::get(context);
1476     Q_ASSERT(data->context == nullptr);
1477     data->context = contextData;
1478     contextData->addObject(data);
1479 }
1480 
1481 /*!
1482   \enum QQmlEngine::ObjectOwnership
1483 
1484   ObjectOwnership controls whether or not QML automatically destroys the
1485   QObject when the corresponding JavaScript object is garbage collected by the
1486   engine. The two ownership options are:
1487 
1488   \value CppOwnership The object is owned by C++ code and QML will never delete
1489   it. The JavaScript destroy() method cannot be used on these objects. This
1490   option is similar to QScriptEngine::QtOwnership.
1491 
1492   \value JavaScriptOwnership The object is owned by JavaScript. When the object
1493   is returned to QML as the return value of a method call, QML will track it
1494   and delete it if there are no remaining JavaScript references to it and
1495   it has no QObject::parent(). An object tracked by one QQmlEngine will be
1496   deleted during that QQmlEngine's destructor. Thus, JavaScript references
1497   between objects with JavaScriptOwnership from two different engines will
1498   not be valid if one of these engines is deleted. This option is similar to
1499   QScriptEngine::ScriptOwnership.
1500 
1501   Generally an application doesn't need to set an object's ownership
1502   explicitly. QML uses a heuristic to set the default ownership. By default, an
1503   object that is created by QML has JavaScriptOwnership. The exception to this
1504   are the root objects created by calling QQmlComponent::create() or
1505   QQmlComponent::beginCreate(), which have CppOwnership by default. The
1506   ownership of these root-level objects is considered to have been transferred
1507   to the C++ caller.
1508 
1509   Objects not-created by QML have CppOwnership by default. The exception to this
1510   are objects returned from C++ method calls; their ownership will be set to
1511   JavaScriptOwnership. This applies only to explicit invocations of Q_INVOKABLE
1512   methods or slots, but not to property getter invocations.
1513 
1514   Calling setObjectOwnership() overrides the default ownership heuristic used by
1515   QML.
1516 */
1517 
1518 /*!
1519   Sets the \a ownership of \a object.
1520 */
setObjectOwnership(QObject * object,ObjectOwnership ownership)1521 void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
1522 {
1523     if (!object)
1524         return;
1525 
1526     QQmlData *ddata = QQmlData::get(object, true);
1527     if (!ddata)
1528         return;
1529 
1530     ddata->indestructible = (ownership == CppOwnership)?true:false;
1531     ddata->explicitIndestructibleSet = true;
1532 }
1533 
1534 /*!
1535   Returns the ownership of \a object.
1536 */
objectOwnership(QObject * object)1537 QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
1538 {
1539     if (!object)
1540         return CppOwnership;
1541 
1542     QQmlData *ddata = QQmlData::get(object, false);
1543     if (!ddata)
1544         return CppOwnership;
1545     else
1546         return ddata->indestructible?CppOwnership:JavaScriptOwnership;
1547 }
1548 
1549 /*!
1550    \reimp
1551 */
event(QEvent * e)1552 bool QQmlEngine::event(QEvent *e)
1553 {
1554     Q_D(QQmlEngine);
1555     if (e->type() == QEvent::User)
1556         d->doDeleteInEngineThread();
1557     else if (e->type() == QEvent::LanguageChange) {
1558         retranslate();
1559     }
1560 
1561     return QJSEngine::event(e);
1562 }
1563 
doDeleteInEngineThread()1564 void QQmlEnginePrivate::doDeleteInEngineThread()
1565 {
1566     QFieldList<Deletable, &Deletable::next> list;
1567     mutex.lock();
1568     list.copyAndClear(toDeleteInEngineThread);
1569     mutex.unlock();
1570 
1571     while (Deletable *d = list.takeFirst())
1572         delete d;
1573 }
1574 
1575 namespace QtQml {
1576 
qmlExecuteDeferred(QObject * object)1577 void qmlExecuteDeferred(QObject *object)
1578 {
1579     QQmlData *data = QQmlData::get(object);
1580 
1581     if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
1582         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
1583 
1584         QQmlComponentPrivate::DeferredState state;
1585         QQmlComponentPrivate::beginDeferred(ep, object, &state);
1586 
1587         // Release the reference for the deferral action (we still have one from construction)
1588         data->releaseDeferredData();
1589 
1590         QQmlComponentPrivate::completeDeferred(ep, &state);
1591     }
1592 }
1593 
qmlContext(const QObject * obj)1594 QQmlContext *qmlContext(const QObject *obj)
1595 {
1596     return QQmlEngine::contextForObject(obj);
1597 }
1598 
qmlEngine(const QObject * obj)1599 QQmlEngine *qmlEngine(const QObject *obj)
1600 {
1601     QQmlData *data = QQmlData::get(obj, false);
1602     if (!data || !data->context)
1603         return nullptr;
1604     return data->context->engine;
1605 }
1606 
resolveAttachedProperties(QQmlAttachedPropertiesFunc pf,QQmlData * data,QObject * object,bool create)1607 static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data,
1608                                           QObject *object, bool create)
1609 {
1610     if (!pf)
1611         return nullptr;
1612 
1613     QObject *rv = data->hasExtendedData() ? data->attachedProperties()->value(pf) : 0;
1614     if (rv || !create)
1615         return rv;
1616 
1617     rv = pf(object);
1618 
1619     if (rv)
1620         data->attachedProperties()->insert(pf, rv);
1621 
1622     return rv;
1623 }
1624 
1625 #if QT_DEPRECATED_SINCE(5, 14)
1626 QT_WARNING_PUSH
1627 QT_WARNING_DISABLE_DEPRECATED
1628 
qmlAttachedPropertiesObjectById(int id,const QObject * object,bool create)1629 QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
1630 {
1631     QQmlData *data = QQmlData::get(object, create);
1632 
1633     // Attached properties are only on objects created by QML,
1634     // unless explicitly requested (create==true)
1635     if (!data)
1636         return nullptr;
1637 
1638     QQmlEnginePrivate *engine = QQmlEnginePrivate::get(data->context);
1639 
1640     const QQmlType type = QQmlMetaType::qmlType(id, QQmlMetaType::TypeIdCategory::QmlType);
1641     return resolveAttachedProperties(type.attachedPropertiesFunction(engine), data,
1642                                      const_cast<QObject *>(object), create);
1643 }
1644 
qmlAttachedPropertiesObject(int * idCache,const QObject * object,const QMetaObject * attachedMetaObject,bool create)1645 QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1646                                      const QMetaObject *attachedMetaObject, bool create)
1647 {
1648     if (*idCache == -1) {
1649         QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
1650         *idCache = QQmlMetaType::attachedPropertiesFuncId(engine ? QQmlEnginePrivate::get(engine) : nullptr, attachedMetaObject);
1651     }
1652 
1653     if (*idCache == -1 || !object)
1654         return nullptr;
1655 
1656     return qmlAttachedPropertiesObjectById(*idCache, object, create);
1657 }
1658 
1659 QT_WARNING_POP
1660 #endif
1661 
qmlAttachedPropertiesFunction(QObject * object,const QMetaObject * attachedMetaObject)1662 QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object,
1663                                                          const QMetaObject *attachedMetaObject)
1664 {
1665     QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
1666     return QQmlMetaType::attachedPropertiesFunc(engine ? QQmlEnginePrivate::get(engine) : nullptr,
1667                                                 attachedMetaObject);
1668 }
1669 
qmlAttachedPropertiesObject(QObject * object,QQmlAttachedPropertiesFunc func,bool create)1670 QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
1671 {
1672     if (!object)
1673         return nullptr;
1674 
1675     QQmlData *data = QQmlData::get(object, create);
1676 
1677     // Attached properties are only on objects created by QML,
1678     // unless explicitly requested (create==true)
1679     if (!data)
1680         return nullptr;
1681 
1682     return resolveAttachedProperties(func, data, object, create);
1683 }
1684 
1685 } // namespace QtQml
1686 
1687 #if QT_DEPRECATED_SINCE(5, 1)
1688 QT_WARNING_PUSH
1689 QT_WARNING_DISABLE_DEPRECATED
1690 
1691 // Also define symbols outside namespace to keep binary compatibility with Qt 5.0
1692 
qmlExecuteDeferred(QObject * obj)1693 Q_QML_EXPORT void qmlExecuteDeferred(QObject *obj)
1694 {
1695     QtQml::qmlExecuteDeferred(obj);
1696 }
1697 
qmlContext(const QObject * obj)1698 Q_QML_EXPORT QQmlContext *qmlContext(const QObject *obj)
1699 {
1700     return QtQml::qmlContext(obj);
1701 }
1702 
qmlEngine(const QObject * obj)1703 Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *obj)
1704 {
1705     return QtQml::qmlEngine(obj);
1706 }
1707 
qmlAttachedPropertiesObjectById(int id,const QObject * obj,bool create)1708 Q_QML_EXPORT QObject *qmlAttachedPropertiesObjectById(int id, const QObject *obj, bool create)
1709 {
1710     return QtQml::qmlAttachedPropertiesObjectById(id, obj, create);
1711 }
1712 
qmlAttachedPropertiesObject(int * idCache,const QObject * object,const QMetaObject * attachedMetaObject,bool create)1713 Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1714                                                   const QMetaObject *attachedMetaObject,
1715                                                   bool create)
1716 {
1717     return QtQml::qmlAttachedPropertiesObject(idCache, object, attachedMetaObject, create);
1718 }
1719 
1720 QT_WARNING_POP
1721 #endif // QT_DEPRECATED_SINCE(5, 1)
1722 
1723 class QQmlDataExtended {
1724 public:
1725     QQmlDataExtended();
1726     ~QQmlDataExtended();
1727 
1728     QHash<QQmlAttachedPropertiesFunc, QObject *> attachedProperties;
1729 };
1730 
QQmlDataExtended()1731 QQmlDataExtended::QQmlDataExtended()
1732 {
1733 }
1734 
~QQmlDataExtended()1735 QQmlDataExtended::~QQmlDataExtended()
1736 {
1737 }
1738 
layout(QQmlNotifierEndpoint * endpoint)1739 void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint)
1740 {
1741     // Add a temporary sentinel at beginning of list. This will be overwritten
1742     // when the end point is inserted into the notifies further down.
1743     endpoint->prev = nullptr;
1744 
1745     while (endpoint->next) {
1746         Q_ASSERT(reinterpret_cast<QQmlNotifierEndpoint *>(endpoint->next->prev) == endpoint);
1747         endpoint = endpoint->next;
1748     }
1749 
1750     while (endpoint) {
1751         QQmlNotifierEndpoint *ep = (QQmlNotifierEndpoint *) endpoint->prev;
1752 
1753         int index = endpoint->sourceSignal;
1754         index = qMin(index, 0xFFFF - 1);
1755 
1756         endpoint->next = notifies[index];
1757         if (endpoint->next) endpoint->next->prev = &endpoint->next;
1758         endpoint->prev = &notifies[index];
1759         notifies[index] = endpoint;
1760 
1761         endpoint = ep;
1762     }
1763 }
1764 
layout()1765 void QQmlData::NotifyList::layout()
1766 {
1767     Q_ASSERT(maximumTodoIndex >= notifiesSize);
1768 
1769     if (todo) {
1770         QQmlNotifierEndpoint **old = notifies;
1771         const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*);
1772         notifies = (QQmlNotifierEndpoint**)realloc(notifies, reallocSize);
1773         const int memsetSize = (maximumTodoIndex - notifiesSize + 1) *
1774                                sizeof(QQmlNotifierEndpoint*);
1775         memset(notifies + notifiesSize, 0, memsetSize);
1776 
1777         if (notifies != old) {
1778             for (int ii = 0; ii < notifiesSize; ++ii)
1779                 if (notifies[ii])
1780                     notifies[ii]->prev = &notifies[ii];
1781         }
1782 
1783         notifiesSize = maximumTodoIndex + 1;
1784 
1785         layout(todo);
1786     }
1787 
1788     maximumTodoIndex = 0;
1789     todo = nullptr;
1790 }
1791 
deferData(int objectIndex,const QQmlRefPointer<QV4::ExecutableCompilationUnit> & compilationUnit,QQmlContextData * context)1792 void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *context)
1793 {
1794     QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
1795     deferData->deferredIdx = objectIndex;
1796     deferData->compilationUnit = compilationUnit;
1797     deferData->context = context;
1798 
1799     const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex);
1800     const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(objectIndex);
1801 
1802     const QV4::CompiledData::Binding *binding = compiledObject->bindingTable();
1803     for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) {
1804         const QQmlPropertyData *property = propertyData.at(i);
1805         if (property && binding->flags & QV4::CompiledData::Binding::IsDeferredBinding)
1806             deferData->bindings.insert(property->coreIndex(), binding);
1807     }
1808 
1809     deferredData.append(deferData);
1810 }
1811 
releaseDeferredData()1812 void QQmlData::releaseDeferredData()
1813 {
1814     auto it = deferredData.begin();
1815     while (it != deferredData.end()) {
1816         DeferredData *deferData = *it;
1817         if (deferData->bindings.isEmpty()) {
1818             delete deferData;
1819             it = deferredData.erase(it);
1820         } else {
1821             ++it;
1822         }
1823     }
1824 }
1825 
addNotify(int index,QQmlNotifierEndpoint * endpoint)1826 void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
1827 {
1828     if (!notifyList) {
1829         notifyList = (NotifyList *)malloc(sizeof(NotifyList));
1830         notifyList->connectionMask = 0;
1831         notifyList->maximumTodoIndex = 0;
1832         notifyList->notifiesSize = 0;
1833         notifyList->todo = nullptr;
1834         notifyList->notifies = nullptr;
1835     }
1836 
1837     Q_ASSERT(!endpoint->isConnected());
1838 
1839     index = qMin(index, 0xFFFF - 1);
1840     notifyList->connectionMask |= (1ULL << quint64(index % 64));
1841 
1842     if (index < notifyList->notifiesSize) {
1843 
1844         endpoint->next = notifyList->notifies[index];
1845         if (endpoint->next) endpoint->next->prev = &endpoint->next;
1846         endpoint->prev = &notifyList->notifies[index];
1847         notifyList->notifies[index] = endpoint;
1848 
1849     } else {
1850         notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
1851 
1852         endpoint->next = notifyList->todo;
1853         if (endpoint->next) endpoint->next->prev = &endpoint->next;
1854         endpoint->prev = &notifyList->todo;
1855         notifyList->todo = endpoint;
1856     }
1857 }
1858 
disconnectNotifiers()1859 void QQmlData::disconnectNotifiers()
1860 {
1861     if (notifyList) {
1862         while (notifyList->todo)
1863             notifyList->todo->disconnect();
1864         for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
1865             while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
1866                 ep->disconnect();
1867         }
1868         free(notifyList->notifies);
1869         free(notifyList);
1870         notifyList = nullptr;
1871     }
1872 }
1873 
attachedProperties() const1874 QHash<QQmlAttachedPropertiesFunc, QObject *> *QQmlData::attachedProperties() const
1875 {
1876     if (!extendedData) extendedData = new QQmlDataExtended;
1877     return &extendedData->attachedProperties;
1878 }
1879 
destroyed(QObject * object)1880 void QQmlData::destroyed(QObject *object)
1881 {
1882     if (nextContextObject)
1883         nextContextObject->prevContextObject = prevContextObject;
1884     if (prevContextObject)
1885         *prevContextObject = nextContextObject;
1886     else if (outerContext && outerContext->contextObjects == this)
1887         outerContext->contextObjects = nextContextObject;
1888 
1889     QQmlAbstractBinding *binding = bindings;
1890     while (binding) {
1891         binding->setAddedToObject(false);
1892         binding = binding->nextBinding();
1893     }
1894     if (bindings && !bindings->ref.deref())
1895         delete bindings;
1896 
1897     compilationUnit = nullptr;
1898 
1899     qDeleteAll(deferredData);
1900     deferredData.clear();
1901 
1902     QQmlBoundSignal *signalHandler = signalHandlers;
1903     while (signalHandler) {
1904         if (signalHandler->isNotifying()) {
1905             // The object is being deleted during signal handler evaluation.
1906             // This will cause a crash due to invalid memory access when the
1907             // evaluation has completed.
1908             // Abort with a friendly message instead.
1909             QString locationString;
1910             QQmlBoundSignalExpression *expr = signalHandler->expression();
1911             if (expr) {
1912                 QQmlSourceLocation location = expr->sourceLocation();
1913                 if (location.sourceFile.isEmpty())
1914                     location.sourceFile = QStringLiteral("<Unknown File>");
1915                 locationString.append(location.sourceFile);
1916                 locationString.append(QStringLiteral(":%0: ").arg(location.line));
1917                 QString source = expr->expression();
1918                 if (source.size() > 100) {
1919                     source.truncate(96);
1920                     source.append(QLatin1String(" ..."));
1921                 }
1922                 locationString.append(source);
1923             } else {
1924                 locationString = QStringLiteral("<Unknown Location>");
1925             }
1926             qFatal("Object %p destroyed while one of its QML signal handlers is in progress.\n"
1927                    "Most likely the object was deleted synchronously (use QObject::deleteLater() "
1928                    "instead), or the application is running a nested event loop.\n"
1929                    "This behavior is NOT supported!\n"
1930                    "%s", object, qPrintable(locationString));
1931         }
1932 
1933         QQmlBoundSignal *next = signalHandler->m_nextSignal;
1934         signalHandler->m_prevSignal = nullptr;
1935         signalHandler->m_nextSignal = nullptr;
1936         delete signalHandler;
1937         signalHandler = next;
1938     }
1939 
1940     if (bindingBitsArraySize > InlineBindingArraySize)
1941         free(bindingBits);
1942 
1943     if (propertyCache)
1944         propertyCache->release();
1945 
1946     ownContext = nullptr;
1947 
1948     while (guards) {
1949         QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
1950         *guard = (QObject *)nullptr;
1951         guard->objectDestroyed(object);
1952     }
1953 
1954     disconnectNotifiers();
1955 
1956     if (extendedData)
1957         delete extendedData;
1958 
1959     // Dispose the handle.
1960     jsWrapper.clear();
1961 
1962     if (ownMemory)
1963         delete this;
1964     else
1965         this->~QQmlData();
1966 }
1967 
1968 DEFINE_BOOL_CONFIG_OPTION(parentTest, QML_PARENT_TEST);
1969 
parentChanged(QObject * object,QObject * parent)1970 void QQmlData::parentChanged(QObject *object, QObject *parent)
1971 {
1972     if (parentTest()) {
1973         if (parentFrozen && !QObjectPrivate::get(object)->wasDeleted) {
1974             QString on;
1975             QString pn;
1976 
1977             { QDebug dbg(&on); dbg << object; on = on.left(on.length() - 1); }
1978             { QDebug dbg(&pn); dbg << parent; pn = pn.left(pn.length() - 1); }
1979 
1980             qFatal("Object %s has had its parent frozen by QML and cannot be changed.\n"
1981                    "User code is attempting to change it to %s.\n"
1982                    "This behavior is NOT supported!", qPrintable(on), qPrintable(pn));
1983         }
1984     }
1985 }
1986 
growBits(QObject * obj,int bit)1987 QQmlData::BindingBitsType *QQmlData::growBits(QObject *obj, int bit)
1988 {
1989     BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
1990     int props = QQmlMetaObject(obj).propertyCount();
1991     Q_ASSERT(bit < 2 * props);
1992     Q_UNUSED(bit); // .. for Q_NO_DEBUG mode when the assert above expands to empty
1993 
1994     uint arraySize = (2 * static_cast<uint>(props) + BitsPerType - 1) / BitsPerType;
1995     Q_ASSERT(arraySize > 1);
1996     Q_ASSERT(arraySize <= 0xffff); // max for bindingBitsArraySize
1997 
1998     BindingBitsType *newBits = static_cast<BindingBitsType *>(malloc(arraySize*sizeof(BindingBitsType)));
1999     memcpy(newBits, bits, bindingBitsArraySize * sizeof(BindingBitsType));
2000     memset(newBits + bindingBitsArraySize, 0, sizeof(BindingBitsType) * (arraySize - bindingBitsArraySize));
2001 
2002     if (bindingBitsArraySize > InlineBindingArraySize)
2003         free(bits);
2004     bindingBits = newBits;
2005     bits = newBits;
2006     bindingBitsArraySize = arraySize;
2007     return bits;
2008 }
2009 
createQQmlData(QObjectPrivate * priv)2010 QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv)
2011 {
2012     Q_ASSERT(priv);
2013     Q_ASSERT(!priv->isDeletingChildren);
2014     priv->declarativeData = new QQmlData;
2015     return static_cast<QQmlData *>(priv->declarativeData);
2016 }
2017 
createPropertyCache(QJSEngine * engine,QObject * object)2018 QQmlPropertyCache *QQmlData::createPropertyCache(QJSEngine *engine, QObject *object)
2019 {
2020     QQmlData *ddata = QQmlData::get(object, /*create*/true);
2021     ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object, -1, true);
2022     return ddata->propertyCache;
2023 }
2024 
sendQuit()2025 void QQmlEnginePrivate::sendQuit()
2026 {
2027     Q_Q(QQmlEngine);
2028     emit q->quit();
2029     if (q->receivers(SIGNAL(quit())) == 0) {
2030         qWarning("Signal QQmlEngine::quit() emitted, but no receivers connected to handle it.");
2031     }
2032 }
2033 
sendExit(int retCode)2034 void QQmlEnginePrivate::sendExit(int retCode)
2035 {
2036     Q_Q(QQmlEngine);
2037     if (q->receivers(SIGNAL(exit(int))) == 0)
2038         qWarning("Signal QQmlEngine::exit() emitted, but no receivers connected to handle it.");
2039     emit q->exit(retCode);
2040 }
2041 
dumpwarning(const QQmlError & error)2042 static void dumpwarning(const QQmlError &error)
2043 {
2044     switch (error.messageType()) {
2045     case QtDebugMsg:
2046         QMessageLogger(error.url().toString().toLatin1().constData(),
2047                        error.line(), nullptr).debug().nospace()
2048                 << qPrintable(error.toString());
2049         break;
2050     case QtInfoMsg:
2051         QMessageLogger(error.url().toString().toLatin1().constData(),
2052                        error.line(), nullptr).info().nospace()
2053                 << qPrintable(error.toString());
2054         break;
2055     case QtWarningMsg:
2056     case QtFatalMsg: // fatal does not support streaming, and furthermore, is actually fatal. Probably not desirable for QML.
2057         QMessageLogger(error.url().toString().toLatin1().constData(),
2058                        error.line(), nullptr).warning().nospace()
2059                 << qPrintable(error.toString());
2060         break;
2061     case QtCriticalMsg:
2062         QMessageLogger(error.url().toString().toLatin1().constData(),
2063                        error.line(), nullptr).critical().nospace()
2064                 << qPrintable(error.toString());
2065         break;
2066     }
2067 }
2068 
dumpwarning(const QList<QQmlError> & errors)2069 static void dumpwarning(const QList<QQmlError> &errors)
2070 {
2071     for (int ii = 0; ii < errors.count(); ++ii)
2072         dumpwarning(errors.at(ii));
2073 }
2074 
warning(const QQmlError & error)2075 void QQmlEnginePrivate::warning(const QQmlError &error)
2076 {
2077     Q_Q(QQmlEngine);
2078     q->warnings(QList<QQmlError>() << error);
2079     if (outputWarningsToMsgLog)
2080         dumpwarning(error);
2081 }
2082 
warning(const QList<QQmlError> & errors)2083 void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
2084 {
2085     Q_Q(QQmlEngine);
2086     q->warnings(errors);
2087     if (outputWarningsToMsgLog)
2088         dumpwarning(errors);
2089 }
2090 
warning(QQmlEngine * engine,const QQmlError & error)2091 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
2092 {
2093     if (engine)
2094         QQmlEnginePrivate::get(engine)->warning(error);
2095     else
2096         dumpwarning(error);
2097 }
2098 
warning(QQmlEngine * engine,const QList<QQmlError> & error)2099 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &error)
2100 {
2101     if (engine)
2102         QQmlEnginePrivate::get(engine)->warning(error);
2103     else
2104         dumpwarning(error);
2105 }
2106 
warning(QQmlEnginePrivate * engine,const QQmlError & error)2107 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
2108 {
2109     if (engine)
2110         engine->warning(error);
2111     else
2112         dumpwarning(error);
2113 }
2114 
warning(QQmlEnginePrivate * engine,const QList<QQmlError> & error)2115 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError> &error)
2116 {
2117     if (engine)
2118         engine->warning(error);
2119     else
2120         dumpwarning(error);
2121 }
2122 
qmlErrorFromDiagnostics(const QString & fileName,const QList<QQmlJS::DiagnosticMessage> & diagnosticMessages)2123 QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(
2124         const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages)
2125 {
2126     QList<QQmlError> errors;
2127     for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
2128         if (m.isWarning()) {
2129             qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message));
2130             continue;
2131         }
2132 
2133         QQmlError error;
2134         error.setUrl(QUrl(fileName));
2135         error.setDescription(m.message);
2136         error.setLine(qmlConvertSourceCoordinate<quint32, int>(m.loc.startLine));
2137         error.setColumn(qmlConvertSourceCoordinate<quint32, int>(m.loc.startColumn));
2138         errors << error;
2139     }
2140     return errors;
2141 }
2142 
cleanupScarceResources()2143 void QQmlEnginePrivate::cleanupScarceResources()
2144 {
2145     // iterate through the list and release them all.
2146     // note that the actual SRD is owned by the JS engine,
2147     // so we cannot delete the SRD; but we can free the
2148     // memory used by the variant in the SRD.
2149     QV4::ExecutionEngine *engine = v4engine();
2150     while (QV4::ExecutionEngine::ScarceResourceData *sr = engine->scarceResources.first()) {
2151         sr->data = QVariant();
2152         engine->scarceResources.remove(sr);
2153     }
2154 }
2155 
2156 /*!
2157   Adds \a path as a directory where the engine searches for
2158   installed modules in a URL-based directory structure.
2159 
2160   The \a path may be a local filesystem directory, a
2161   \l {The Qt Resource System}{Qt Resource} path (\c {:/imports}), a
2162   \l {The Qt Resource System}{Qt Resource} url (\c {qrc:/imports}) or a URL.
2163 
2164   The \a path will be converted into canonical form before it
2165   is added to the import path list.
2166 
2167   The newly added \a path will be first in the importPathList().
2168 
2169   \sa setImportPathList(), {QML Modules}
2170 */
addImportPath(const QString & path)2171 void QQmlEngine::addImportPath(const QString& path)
2172 {
2173     Q_D(QQmlEngine);
2174     d->importDatabase.addImportPath(path);
2175 }
2176 
2177 /*!
2178   Returns the list of directories where the engine searches for
2179   installed modules in a URL-based directory structure.
2180 
2181   For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
2182   imports \c com.mycompany.Feature will cause the QQmlEngine to look
2183   in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
2184   provided by that module. A \c qmldir file is required for defining the
2185   type version mapping and possibly QML extensions plugins.
2186 
2187   By default, the list contains the directory of the application executable,
2188   paths specified in the \c QML2_IMPORT_PATH environment variable,
2189   and the builtin \c Qml2ImportsPath from QLibraryInfo.
2190 
2191   \sa addImportPath(), setImportPathList()
2192 */
importPathList() const2193 QStringList QQmlEngine::importPathList() const
2194 {
2195     Q_D(const QQmlEngine);
2196     return d->importDatabase.importPathList();
2197 }
2198 
2199 /*!
2200   Sets \a paths as the list of directories where the engine searches for
2201   installed modules in a URL-based directory structure.
2202 
2203   By default, the list contains the directory of the application executable,
2204   paths specified in the \c QML2_IMPORT_PATH environment variable,
2205   and the builtin \c Qml2ImportsPath from QLibraryInfo.
2206 
2207   \sa importPathList(), addImportPath()
2208   */
setImportPathList(const QStringList & paths)2209 void QQmlEngine::setImportPathList(const QStringList &paths)
2210 {
2211     Q_D(QQmlEngine);
2212     d->importDatabase.setImportPathList(paths);
2213 }
2214 
2215 
2216 /*!
2217   Adds \a path as a directory where the engine searches for
2218   native plugins for imported modules (referenced in the \c qmldir file).
2219 
2220   By default, the list contains only \c .,  i.e. the engine searches
2221   in the directory of the \c qmldir file itself.
2222 
2223   The newly added \a path will be first in the pluginPathList().
2224 
2225   \sa setPluginPathList()
2226 */
addPluginPath(const QString & path)2227 void QQmlEngine::addPluginPath(const QString& path)
2228 {
2229     Q_D(QQmlEngine);
2230     d->importDatabase.addPluginPath(path);
2231 }
2232 
2233 
2234 /*!
2235   Returns the list of directories where the engine searches for
2236   native plugins for imported modules (referenced in the \c qmldir file).
2237 
2238   By default, the list contains only \c .,  i.e. the engine searches
2239   in the directory of the \c qmldir file itself.
2240 
2241   \sa addPluginPath(), setPluginPathList()
2242 */
pluginPathList() const2243 QStringList QQmlEngine::pluginPathList() const
2244 {
2245     Q_D(const QQmlEngine);
2246     return d->importDatabase.pluginPathList();
2247 }
2248 
2249 /*!
2250   Sets the list of directories where the engine searches for
2251   native plugins for imported modules (referenced in the \c qmldir file)
2252   to \a paths.
2253 
2254   By default, the list contains only \c .,  i.e. the engine searches
2255   in the directory of the \c qmldir file itself.
2256 
2257   \sa pluginPathList(), addPluginPath()
2258   */
setPluginPathList(const QStringList & paths)2259 void QQmlEngine::setPluginPathList(const QStringList &paths)
2260 {
2261     Q_D(QQmlEngine);
2262     d->importDatabase.setPluginPathList(paths);
2263 }
2264 
2265 #if QT_CONFIG(library)
2266 /*!
2267   Imports the plugin named \a filePath with the \a uri provided.
2268   Returns true if the plugin was successfully imported; otherwise returns false.
2269 
2270   On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
2271 
2272   The plugin has to be a Qt plugin which implements the QQmlEngineExtensionPlugin interface.
2273 */
importPlugin(const QString & filePath,const QString & uri,QList<QQmlError> * errors)2274 bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
2275 {
2276     Q_D(QQmlEngine);
2277     return d->importDatabase.importDynamicPlugin(filePath, uri, QString(), -1, errors);
2278 }
2279 #endif
2280 
2281 /*!
2282   \property QQmlEngine::offlineStoragePath
2283   \brief the directory for storing offline user data
2284 
2285   Returns the directory where SQL and other offline
2286   storage is placed.
2287 
2288   The SQL databases created with openDatabase() are stored here.
2289 
2290   The default is QML/OfflineStorage in the platform-standard
2291   user application data directory.
2292 
2293   Note that the path may not currently exist on the filesystem, so
2294   callers wanting to \e create new files at this location should create
2295   it first - see QDir::mkpath().
2296 */
setOfflineStoragePath(const QString & dir)2297 void QQmlEngine::setOfflineStoragePath(const QString& dir)
2298 {
2299     Q_D(QQmlEngine);
2300     d->offlineStoragePath = dir;
2301 }
2302 
offlineStoragePath() const2303 QString QQmlEngine::offlineStoragePath() const
2304 {
2305     Q_D(const QQmlEngine);
2306 
2307     if (d->offlineStoragePath.isEmpty()) {
2308         QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
2309         QQmlEnginePrivate *e = const_cast<QQmlEnginePrivate *>(d);
2310         if (!dataLocation.isEmpty())
2311             e->offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
2312                                   + QDir::separator() + QLatin1String("QML")
2313                                   + QDir::separator() + QLatin1String("OfflineStorage");
2314     }
2315 
2316     return d->offlineStoragePath;
2317 }
2318 
2319 /*!
2320   Returns the file path where a \l{QtQuick.LocalStorage}{Local Storage}
2321   database with the identifier \a databaseName is (or would be) located.
2322 
2323   \sa {openDatabaseSync}{LocalStorage.openDatabaseSync()}
2324   \since 5.9
2325 */
offlineStorageDatabaseFilePath(const QString & databaseName) const2326 QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName) const
2327 {
2328     Q_D(const QQmlEngine);
2329     QCryptographicHash md5(QCryptographicHash::Md5);
2330     md5.addData(databaseName.toUtf8());
2331     return d->offlineStorageDatabaseDirectory() + QLatin1String(md5.result().toHex());
2332 }
2333 
2334 // #### Qt 6: Remove this function, it exists only for binary compatibility.
2335 /*!
2336  * \internal
2337  */
addNamedBundle(const QString & name,const QString & fileName)2338 bool QQmlEngine::addNamedBundle(const QString &name, const QString &fileName)
2339 {
2340     Q_UNUSED(name)
2341     Q_UNUSED(fileName)
2342     return false;
2343 }
2344 
offlineStorageDatabaseDirectory() const2345 QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const
2346 {
2347     Q_Q(const QQmlEngine);
2348     return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator();
2349 }
2350 
isQObject(int t)2351 bool QQmlEnginePrivate::isQObject(int t)
2352 {
2353     Locker locker(this);
2354     return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t);
2355 }
2356 
toQObject(const QVariant & v,bool * ok) const2357 QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
2358 {
2359     Locker locker(this);
2360     int t = v.userType();
2361     if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
2362         if (ok) *ok = true;
2363         return *(QObject *const *)(v.constData());
2364     } else {
2365         return QQmlMetaType::toQObject(v, ok);
2366     }
2367 }
2368 
typeCategory(int t) const2369 QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
2370 {
2371     Locker locker(this);
2372     if (m_compositeTypes.contains(t))
2373         return QQmlMetaType::Object;
2374     return QQmlMetaType::typeCategory(t);
2375 }
2376 
isList(int t) const2377 bool QQmlEnginePrivate::isList(int t) const
2378 {
2379     return QQmlMetaType::isList(t);
2380 }
2381 
listType(int t) const2382 int QQmlEnginePrivate::listType(int t) const
2383 {
2384     return QQmlMetaType::listType(t);
2385 }
2386 
2387 
propertyCacheForPotentialInlineComponentType(int t,const QHash<int,QV4::ExecutableCompilationUnit * >::const_iterator & iter)2388 static QQmlPropertyCache *propertyCacheForPotentialInlineComponentType(int t, const QHash<int, QV4::ExecutableCompilationUnit *>::const_iterator &iter) {
2389     if (t != (*iter)->metaTypeId) {
2390         // this is an inline component, and what we have in the iterator is currently the parent compilation unit
2391         for (auto &&icDatum: (*iter)->inlineComponentData)
2392             if (icDatum.typeIds.id == t)
2393                 return (*iter)->propertyCaches.at(icDatum.objectIndex);
2394     }
2395     return (*iter)->rootPropertyCache().data();
2396 }
2397 
rawMetaObjectForType(int t) const2398 QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
2399 {
2400     Locker locker(this);
2401     auto iter = m_compositeTypes.constFind(t);
2402     if (iter != m_compositeTypes.cend()) {
2403         return propertyCacheForPotentialInlineComponentType(t, iter);
2404     } else {
2405         QQmlType type = QQmlMetaType::qmlType(t);
2406         return QQmlMetaObject(type.baseMetaObject());
2407     }
2408 }
2409 
metaObjectForType(int t) const2410 QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
2411 {
2412     Locker locker(this);
2413     auto iter = m_compositeTypes.constFind(t);
2414     if (iter != m_compositeTypes.cend()) {
2415         return propertyCacheForPotentialInlineComponentType(t, iter);
2416     } else {
2417         QQmlType type = QQmlMetaType::qmlType(t);
2418         return QQmlMetaObject(type.metaObject());
2419     }
2420 }
2421 
propertyCacheForType(int t)2422 QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
2423 {
2424     Locker locker(this);
2425     auto iter = m_compositeTypes.constFind(t);
2426     if (iter != m_compositeTypes.cend()) {
2427         return propertyCacheForPotentialInlineComponentType(t, iter);
2428     } else {
2429         QQmlType type = QQmlMetaType::qmlType(t);
2430         locker.unlock();
2431         return type.isValid() ? cache(type.metaObject()) : nullptr;
2432     }
2433 }
2434 
rawPropertyCacheForType(int t,int minorVersion)2435 QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, int minorVersion)
2436 {
2437     Locker locker(this);
2438     auto iter = m_compositeTypes.constFind(t);
2439     if (iter != m_compositeTypes.cend()) {
2440         return propertyCacheForPotentialInlineComponentType(t, iter);
2441     } else {
2442         QQmlType type = QQmlMetaType::qmlType(t);
2443         locker.unlock();
2444 
2445         if (minorVersion >= 0)
2446             return type.isValid() ? cache(type, minorVersion) : nullptr;
2447         else
2448             return type.isValid() ? cache(type.baseMetaObject()) : nullptr;
2449     }
2450 }
2451 
registerInternalCompositeType(QV4::ExecutableCompilationUnit * compilationUnit)2452 void QQmlEnginePrivate::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
2453 {
2454     compilationUnit->isRegisteredWithEngine = true;
2455 
2456     Locker locker(this);
2457     // The QQmlCompiledData is not referenced here, but it is removed from this
2458     // hash in the QQmlCompiledData destructor
2459     m_compositeTypes.insert(compilationUnit->metaTypeId, compilationUnit);
2460     for (auto &&data: compilationUnit->inlineComponentData) {
2461         m_compositeTypes.insert(data.typeIds.id, compilationUnit);
2462     }
2463 }
2464 
unregisterInternalCompositeType(QV4::ExecutableCompilationUnit * compilationUnit)2465 void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
2466 {
2467     compilationUnit->isRegisteredWithEngine = false;
2468 
2469     Locker locker(this);
2470     m_compositeTypes.remove(compilationUnit->metaTypeId);
2471     for (auto&& icDatum: compilationUnit->inlineComponentData)
2472         m_compositeTypes.remove(icDatum.typeIds.id);
2473 }
2474 
obtainExecutableCompilationUnit(int typeId)2475 QV4::ExecutableCompilationUnit *QQmlEnginePrivate::obtainExecutableCompilationUnit(int typeId)
2476 {
2477     Locker locker(this);
2478     return m_compositeTypes.value(typeId, nullptr);
2479 }
2480 
2481 template<>
singletonInstance(const QQmlType & type)2482 QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
2483 {
2484     Q_Q(QQmlEngine);
2485 
2486     QJSValue value = singletonInstances.value(type);
2487     if (!value.isUndefined()) {
2488         return value;
2489     }
2490 
2491     QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
2492     Q_ASSERT(siinfo != nullptr);
2493 
2494     if (siinfo->scriptCallback) {
2495         value = siinfo->scriptCallback(q, q);
2496         if (value.isQObject()) {
2497             QObject *o = value.toQObject();
2498             // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
2499             // should behave identically to QML singleton types.
2500             q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
2501         }
2502         singletonInstances.insert(type, value);
2503 
2504     } else if (siinfo->qobjectCallback) {
2505         QObject *o = siinfo->qobjectCallback(q, q);
2506         if (!o) {
2507             QQmlError error;
2508             error.setMessageType(QtMsgType::QtCriticalMsg);
2509             error.setDescription(QString::asprintf("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.",
2510                                                    qPrintable(QString::fromUtf8(type.typeName()))));
2511             warning(error);
2512         } else {
2513             // if this object can use a property cache, create it now
2514             QQmlData::ensurePropertyCache(q, o);
2515         }
2516         // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
2517         // should behave identically to QML singleton types.
2518         q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
2519         value = q->newQObject(o);
2520         singletonInstances.insert(type, value);
2521     } else if (!siinfo->url.isEmpty()) {
2522         QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
2523         QObject *o = component.beginCreate(q->rootContext());
2524         value = q->newQObject(o);
2525         singletonInstances.insert(type, value);
2526         component.completeCreate();
2527     }
2528 
2529     return value;
2530 }
2531 
destroySingletonInstance(const QQmlType & type)2532 void QQmlEnginePrivate::destroySingletonInstance(const QQmlType &type)
2533 {
2534     Q_ASSERT(type.isSingleton() || type.isCompositeSingleton());
2535 
2536     QObject* o = singletonInstances.take(type).toQObject();
2537     if (o) {
2538         QQmlData *ddata = QQmlData::get(o, false);
2539         if (type.singletonInstanceInfo()->url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet)
2540             return;
2541         delete o;
2542     }
2543 }
2544 
isTypeLoaded(const QUrl & url) const2545 bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
2546 {
2547     return typeLoader.isTypeLoaded(url);
2548 }
2549 
isScriptLoaded(const QUrl & url) const2550 bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
2551 {
2552     return typeLoader.isScriptLoaded(url);
2553 }
2554 
2555 #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
2556 // Normalize a file name using Shell API. As opposed to converting it
2557 // to a short 8.3 name and back, this also works for drives where 8.3 notation
2558 // is disabled (see 8dot3name options of fsutil.exe).
shellNormalizeFileName(const QString & name)2559 static inline QString shellNormalizeFileName(const QString &name)
2560 {
2561     const QString nativeSeparatorName(QDir::toNativeSeparators(name));
2562     const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(nativeSeparatorName.utf16());
2563 // The correct declaration of the SHGetPathFromIDList symbol is
2564 // being used in mingw-w64 as of r6215, which is a v3 snapshot.
2565 #if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3)
2566     ITEMIDLIST *file;
2567     if (FAILED(SHParseDisplayName(nameC, NULL, reinterpret_cast<LPITEMIDLIST>(&file), 0, NULL)))
2568         return name;
2569 #else
2570     PIDLIST_ABSOLUTE file;
2571     if (FAILED(SHParseDisplayName(nameC, NULL, &file, 0, NULL)))
2572         return name;
2573 #endif
2574     TCHAR buffer[MAX_PATH];
2575     bool gotPath = SHGetPathFromIDList(file, buffer);
2576     ILFree(file);
2577 
2578     if (!gotPath)
2579         return name;
2580 
2581     QString canonicalName = QString::fromWCharArray(buffer);
2582     // Upper case drive letter
2583     if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':'))
2584         canonicalName[0] = canonicalName.at(0).toUpper();
2585     return QDir::cleanPath(canonicalName);
2586 }
2587 #endif // Q_OS_WIN && !Q_OS_WINRT
2588 
QQml_isFileCaseCorrect(const QString & fileName,int lengthIn)2589 bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
2590 {
2591 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
2592     QFileInfo info(fileName);
2593     const QString absolute = info.absoluteFilePath();
2594 
2595 #if defined(Q_OS_DARWIN) || defined(Q_OS_WINRT)
2596     const QString canonical = info.canonicalFilePath();
2597 #elif defined(Q_OS_WIN)
2598     // No difference if the path is qrc based
2599     if (absolute[0] == QLatin1Char(':'))
2600         return true;
2601     const QString canonical = shellNormalizeFileName(absolute);
2602 #endif
2603 
2604     const int absoluteLength = absolute.length();
2605     const int canonicalLength = canonical.length();
2606 
2607     int length = qMin(absoluteLength, canonicalLength);
2608     if (lengthIn >= 0) {
2609         length = qMin(lengthIn, length);
2610     } else {
2611         // No length given: Limit to file name. Do not trigger
2612         // on drive letters or folder names.
2613         int lastSlash = absolute.lastIndexOf(QLatin1Char('/'));
2614         if (lastSlash < 0)
2615             lastSlash = absolute.lastIndexOf(QLatin1Char('\\'));
2616         if (lastSlash >= 0) {
2617             const int fileNameLength = absoluteLength - 1 - lastSlash;
2618             length = qMin(length, fileNameLength);
2619         }
2620     }
2621 
2622     for (int ii = 0; ii < length; ++ii) {
2623         const QChar &a = absolute.at(absoluteLength - 1 - ii);
2624         const QChar &c = canonical.at(canonicalLength - 1 - ii);
2625 
2626         if (a.toLower() != c.toLower())
2627             return true;
2628         if (a != c)
2629             return false;
2630     }
2631 #else
2632     Q_UNUSED(lengthIn)
2633     Q_UNUSED(fileName)
2634 #endif
2635     return true;
2636 }
2637 
2638 /*!
2639     \fn QQmlEngine *qmlEngine(const QObject *object)
2640     \relates QQmlEngine
2641 
2642     Returns the QQmlEngine associated with \a object, if any.  This is equivalent to
2643     QQmlEngine::contextForObject(object)->engine(), but more efficient.
2644 
2645     \note Add \c{#include <QtQml>} to use this function.
2646 
2647     \sa {QQmlEngine::contextForObject()}{contextForObject()}, qmlContext()
2648 */
2649 
2650 /*!
2651     \fn QQmlContext *qmlContext(const QObject *object)
2652     \relates QQmlEngine
2653 
2654     Returns the QQmlContext associated with \a object, if any.  This is equivalent to
2655     QQmlEngine::contextForObject(object).
2656 
2657     \note Add \c{#include <QtQml>} to use this function.
2658 
2659     \sa {QQmlEngine::contextForObject()}{contextForObject()}, qmlEngine()
2660 */
2661 
2662 QT_END_NAMESPACE
2663 
2664 #include "moc_qqmlengine.cpp"
2665