aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dist/changes-5.9.483
-rw-r--r--examples/quick/externaldraganddrop/DragAndDropTextItem.qml46
-rw-r--r--examples/quick/externaldraganddrop/externaldraganddrop.pro3
-rw-r--r--examples/quick/externaldraganddrop/externaldraganddrop.qml2
-rw-r--r--examples/quick/scenegraph/threadedanimation/spinner.cpp7
-rw-r--r--examples/quick/shared/shared.h7
-rw-r--r--src/3rdparty/masm/assembler/ARM64Assembler.h7
-rw-r--r--src/3rdparty/masm/wtf/MathExtras.h5
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp21
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp32
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp73
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h11
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp10
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h5
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp13
-rw-r--r--src/qml/compiler/qv4codegen.cpp3
-rw-r--r--src/qml/compiler/qv4codegen_p.h1
-rw-r--r--src/qml/compiler/qv4compileddata.cpp3
-rw-r--r--src/qml/compiler/qv4compileddata_p.h22
-rw-r--r--src/qml/compiler/qv4compiler.cpp2
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h1
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h19
-rw-r--r--src/qml/doc/src/includes/qqmlcomponent.qdoc58
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc39
-rw-r--r--src/qml/doc/src/qtqml.qdoc5
-rw-r--r--src/qml/jsruntime/qv4engine.cpp6
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h2
-rw-r--r--src/qml/jsruntime/qv4function_p.h1
-rw-r--r--src/qml/jsruntime/qv4global_p.h4
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h2
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp6
-rw-r--r--src/qml/jsruntime/qv4runtimecodegen.cpp1
-rw-r--r--src/qml/jsruntime/qv4script.cpp12
-rw-r--r--src/qml/jsruntime/qv4script_p.h6
-rw-r--r--src/qml/memory/qv4mm.cpp151
-rw-r--r--src/qml/memory/qv4mm_p.h25
-rw-r--r--src/qml/qml.pro2
-rw-r--r--src/qml/qml/qqmlcomponent.cpp35
-rw-r--r--src/qml/qml/qqmlcontext.cpp4
-rw-r--r--src/qml/qml/qqmldata_p.h31
-rw-r--r--src/qml/qml/qqmlengine.cpp60
-rw-r--r--src/qml/qml/qqmlincubator.cpp19
-rw-r--r--src/qml/qml/qqmlincubator_p.h3
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp27
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h12
-rw-r--r--src/qml/qml/qqmlproperty.cpp150
-rw-r--r--src/qml/qml/qqmlproperty_p.h2
-rw-r--r--src/qml/qml/qqmltypeloader.cpp83
-rw-r--r--src/qml/qml/qqmltypeloader_p.h2
-rw-r--r--src/qml/qml/qqmlvme.cpp12
-rw-r--r--src/qml/qml/qqmlvme_p.h1
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp12
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc53
-rw-r--r--src/quick/doc/src/qtquick.qdoc3
-rw-r--r--src/quick/items/qquickanimatedimage.cpp120
-rw-r--r--src/quick/items/qquickanimatedimage_p_p.h21
-rw-r--r--src/quick/items/qquickflickable.cpp14
-rw-r--r--src/quick/items/qquickflickable_p_p.h4
-rw-r--r--src/quick/items/qquickframebufferobject.cpp1
-rw-r--r--src/quick/items/qquickgridview.cpp14
-rw-r--r--src/quick/items/qquickitem.cpp35
-rw-r--r--src/quick/items/qquickitem_p.h3
-rw-r--r--src/quick/items/qquickitemsmodule.cpp6
-rw-r--r--src/quick/items/qquickitemview.cpp76
-rw-r--r--src/quick/items/qquickitemviewtransition_p.h18
-rw-r--r--src/quick/items/qquicklistview.cpp3
-rw-r--r--src/quick/items/qquickloader.cpp2
-rw-r--r--src/quick/items/qquickrepeater.cpp5
-rw-r--r--src/quick/items/qquickwindow.cpp56
-rw-r--r--src/quick/items/qquickwindow.h6
-rw-r--r--src/quick/items/qquickwindowmodule.cpp2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp10
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h4
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp3
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp2
-rw-r--r--src/quick/util/qquickanimationcontroller.cpp2
-rw-r--r--src/quick/util/qquickpropertychanges.cpp33
-rw-r--r--src/quick/util/qquickshortcut.cpp3
-rw-r--r--src/quick/util/qquickstate.cpp5
-rw-r--r--src/quick/util/qquickstate_p.h4
-rw-r--r--src/quick/util/qquicktransition.cpp29
-rw-r--r--src/quick/util/qquicktransition_p.h15
-rw-r--r--src/quickwidgets/qquickwidget.cpp53
-rw-r--r--tests/auto/particles/qquickcustomaffector/BLACKLIST2
-rw-r--r--tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp15
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp3
-rw-r--r--tests/auto/qml/qml.pro1
-rw-r--r--tests/auto/qml/qmlplugindump/qmlplugindump.pro3
-rw-r--r--tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp4
-rw-r--r--tests/auto/qml/qqmlcomponent/data/QtObjectComponent#2.qml3
-rw-r--r--tests/auto/qml/qqmlcomponent/data/QtObjectComponent.qml3
-rw-r--r--tests/auto/qml/qqmlcomponent/qqmlcomponent.pro2
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp24
-rw-r--r--tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp21
-rw-r--r--tests/auto/qml/qqmllanguage/data/accessDeletedObject.qml12
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAlias.12.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAlias.12.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp25
-rw-r--r--tests/auto/qml/qqmltypeloader/data/ComponentWithIncubator.qml9
-rw-r--r--tests/auto/qml/qqmltypeloader/data/trim_cache3.qml14
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp21
-rw-r--r--tests/auto/quick/qquickgridview/data/qtbug49218.qml126
-rw-r--r--tests/auto/quick/qquickgridview/tst_qquickgridview.cpp31
-rw-r--r--tests/auto/quick/qquicklistview/data/addoncompleted.qml90
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp47
-rw-r--r--tests/auto/quick/qquickshortcut/data/shortcutsRect.qml54
-rw-r--r--tests/auto/quick/qquickshortcut/qquickshortcut.pro3
-rw-r--r--tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp124
-rw-r--r--tests/auto/quick/touchmouse/BLACKLIST2
-rw-r--r--tests/auto/quickwidgets/qquickwidget/data/mouse.qml18
-rw-r--r--tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp29
-rw-r--r--tests/benchmarks/qml/animation/tst_animation.cpp6
-rw-r--r--tests/benchmarks/qml/holistic/tst_holistic.cpp18
-rw-r--r--tests/manual/scenegraph_lancelot/data/text/text_emoji_hebrew.qml45
-rw-r--r--tests/manual/scenegraph_lancelot/data/text/text_emoji_zwj.qml45
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp27
-rw-r--r--tools/qmljs/qmljs.cpp1
118 files changed, 1866 insertions, 725 deletions
diff --git a/dist/changes-5.9.4 b/dist/changes-5.9.4
new file mode 100644
index 0000000000..0659875b9a
--- /dev/null
+++ b/dist/changes-5.9.4
@@ -0,0 +1,83 @@
+Qt 5.9.4 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.9.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+http://doc.qt.io/qt-5/index.html
+
+The Qt version 5.9 series is binary compatible with the 5.8.x series.
+Applications compiled for 5.8 will continue to run with 5.9.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.9.4 Changes *
+****************************************************************************
+
+QtQml
+-----
+
+ - Added qt.qml.gc.statistics and qt.qml.gc.allocatorStats logging
+ categories for garbage collection statistics
+ - [QTBUG-56521][QTBUG-56532] Added private qmlUnregisterType(int) for
+ advanced use cases such as re-registering an enum, or cleaning up
+ when a plugin is unloaded
+ - [QTBUG-61209] Fixed handling of QML cache files during URL interception.
+ This changes the semantics of URL redirects. Previously a redirected URL
+ was used as the base URL for further URL resolution. This doesn't work
+ because redirection occurs after interception and interception should
+ not influence the resolution of further URLs. We now use the original
+ URL as base URL for resolution of further URLs and rely on the server to
+ redirect those, too.
+ - [QTBUG-63844] Fixed a crash in QMetaObject::activate() when using
+ a Loader to load items with animations
+
+QtQuick
+-------
+
+ - QQuickWindow:
+ * Added logging category qt.quick.window.transient to check detection of
+ transient windows declared inside other Items and Windows
+
+ - QQuickWidget:
+ * [QTBUG-64241] Synthesized mouse events delivered via QQuickWidget
+ have QMouseEvent::source() set so they can be identified as synthesized
+ * [QTBUG-64548] Shortcut now works in QQuickWidget
+ * Fixed coordinate transformation in QInputMethodQueryEvent as delivered
+ to QQuickWidget
+
+ - Input Handling:
+ * [QTBUG-53036] When an application is deactivated (applicationState() is
+ no longer ApplicationActive), it's treated the same as window deactivation.
+ Thus on mobile devices MouseAreas no longer get stuck in pressed state, etc.
+ * [QTBUG-61144] Fixed the regression that when a mouse-handling Item
+ or Control is used in a Flickable with a pressDelay, the delegate item
+ did not receive touchscreen taps (in the form of mouse clicks)
+ * [QTBUG-63026] Flickable no longer jumps when reversing the direction of
+ scrolling on a pixel-delta-capable trackpad
+ * [QTBUG-64249] When pressing one MouseArea via mouse, then tapping another
+ via touch, then releasing, the first MouseArea correctly gets released
+
+ - Item Views:
+ * [QTBUG-46488] Refilling is restarted when necessary due to changing
+ the model in a delegate's Component.onCompleted()
+ * [QTBUG-50992] Fixed a bug which caused Qt Quick Controls to often be
+ "destroyed during incubation" during asynchronous creation
+ * [QTBUG-54859] Fixed a crash when items in a Repeater are moved around
+ during asynchronous creation
+ * [QTBUG-61537] Fixed incorrect delegate geometry due to model changes
+ during delegate creation
+ * [QTBUG-62864] Fixed incorrect ListView and GridView highlight position
+ while scrolling through delegates backed by a lazy-loading model
+ * [QTBUG-63743] Fixed a bug with clipping of items in a ScrollView
+
+ - Other:
+ * [QTBUG-62913] AnimatedImage.frameCount now has a NOTIFY signal
+ * [QTBUG-65156] Fixed a memory leak by releasing textures during resizing
diff --git a/examples/quick/externaldraganddrop/DragAndDropTextItem.qml b/examples/quick/externaldraganddrop/DragAndDropTextItem.qml
index 7499c83e6d..9858a961c9 100644
--- a/examples/quick/externaldraganddrop/DragAndDropTextItem.qml
+++ b/examples/quick/externaldraganddrop/DragAndDropTextItem.qml
@@ -49,32 +49,36 @@
****************************************************************************/
import QtQuick 2.2
+import "../shared" as Examples
Rectangle {
id: item
property string display
- color: "#EEE"
+ property alias dropEnabled: acceptDropCB.checked
+ color: dropArea.containsDrag ? "#CFC" : "#EEE"
+ ColorAnimation on color {
+ id: rejectAnimation
+ from: "#FCC"
+ to: "#EEE"
+ duration: 1000
+ }
Text {
anchors.fill: parent
text: item.display
wrapMode: Text.WordWrap
}
DropArea {
+ id: dropArea
anchors.fill: parent
keys: ["text/plain"]
- onEntered: {
- item.color = "#FCC"
- }
- onExited: {
- item.color = "#EEE"
+ onEntered: if (!acceptDropCB.checked) {
+ drag.accepted = false
+ rejectAnimation.start()
}
- onDropped: {
- item.color = "#EEE"
- if (drop.hasText) {
- if (drop.proposedAction == Qt.MoveAction || drop.proposedAction == Qt.CopyAction) {
- item.display = drop.text
- drop.acceptProposedAction()
- }
+ onDropped: if (drop.hasText && acceptDropCB.checked) {
+ if (drop.proposedAction == Qt.MoveAction || drop.proposedAction == Qt.CopyAction) {
+ item.display = drop.text
+ drop.acceptProposedAction()
}
}
}
@@ -91,12 +95,12 @@ Rectangle {
Drag.hotSpot.y: 0
Drag.mimeData: { "text/plain": item.display }
Drag.dragType: Drag.Automatic
- Drag.onDragStarted: {
- }
- Drag.onDragFinished: {
- if (dropAction == Qt.MoveAction) {
- item.display = ""
- }
- }
- } // Item
+ Drag.onDragFinished: if (dropAction == Qt.MoveAction) item.display = ""
+ }
+ Examples.CheckBox {
+ id: acceptDropCB
+ anchors.right: parent.right
+ checked: true
+ text: "accept drop"
+ }
}
diff --git a/examples/quick/externaldraganddrop/externaldraganddrop.pro b/examples/quick/externaldraganddrop/externaldraganddrop.pro
index 646781e7d1..0a592a84f3 100644
--- a/examples/quick/externaldraganddrop/externaldraganddrop.pro
+++ b/examples/quick/externaldraganddrop/externaldraganddrop.pro
@@ -2,9 +2,10 @@ TEMPLATE = app
QT += quick qml
SOURCES += main.cpp
-RESOURCES += externaldraganddrop.qrc
+RESOURCES += externaldraganddrop.qrc ../shared/shared.qrc
EXAMPLE_FILES = \
+ externaldraganddrop.qml \
DragAndDropTextItem.qml
target.path = $$[QT_INSTALL_EXAMPLES]/quick/externaldraganddrop
diff --git a/examples/quick/externaldraganddrop/externaldraganddrop.qml b/examples/quick/externaldraganddrop/externaldraganddrop.qml
index 9c33d1e468..47a76a259a 100644
--- a/examples/quick/externaldraganddrop/externaldraganddrop.qml
+++ b/examples/quick/externaldraganddrop/externaldraganddrop.qml
@@ -82,8 +82,8 @@ Item {
DragAndDropTextItem {
Layout.fillWidth: true
height: 142
+ dropEnabled: false
display: "Drag out into other applications."
}
-
}
}
diff --git a/examples/quick/scenegraph/threadedanimation/spinner.cpp b/examples/quick/scenegraph/threadedanimation/spinner.cpp
index 7b4281aafc..83c4494720 100644
--- a/examples/quick/scenegraph/threadedanimation/spinner.cpp
+++ b/examples/quick/scenegraph/threadedanimation/spinner.cpp
@@ -66,8 +66,8 @@ public:
, m_spinning(false)
, m_window(window)
{
- connect(window, &QQuickWindow::beforeRendering, this, &SpinnerNode::maybeRotate);
- connect(window, &QQuickWindow::frameSwapped, this, &SpinnerNode::maybeUpdate);
+ connect(window, &QQuickWindow::beforeRendering, this, &SpinnerNode::maybeRotate, Qt::DirectConnection);
+ connect(window, &QQuickWindow::frameSwapped, this, &SpinnerNode::maybeUpdate, Qt::DirectConnection);
QImage image(":/scenegraph/threadedanimation/spinner.png");
m_texture = window->createTextureFromImage(image);
@@ -96,6 +96,9 @@ public slots:
matrix.rotate(m_rotation, 0, 0, 1);
matrix.translate(-32, -32);
setMatrix(matrix);
+
+ // If we're inside a QQuickWidget, this call is necessary to ensure the widget gets updated.
+ m_window->update();
}
}
diff --git a/examples/quick/shared/shared.h b/examples/quick/shared/shared.h
index c25d0475af..18e7ff056b 100644
--- a/examples/quick/shared/shared.h
+++ b/examples/quick/shared/shared.h
@@ -77,11 +77,6 @@
if (view.status() == QQuickView::Error)\
return -1;\
view.setResizeMode(QQuickView::SizeRootObjectToView);\
- if (QGuiApplication::platformName() == QLatin1String("qnx") || \
- QGuiApplication::platformName() == QLatin1String("eglfs")) {\
- view.showFullScreen();\
- } else {\
- view.show();\
- }\
+ view.show();\
return app.exec();\
}
diff --git a/src/3rdparty/masm/assembler/ARM64Assembler.h b/src/3rdparty/masm/assembler/ARM64Assembler.h
index 7390997af1..008f03bccf 100644
--- a/src/3rdparty/masm/assembler/ARM64Assembler.h
+++ b/src/3rdparty/masm/assembler/ARM64Assembler.h
@@ -3032,6 +3032,13 @@ public:
linuxPageFlush(current, current + page);
linuxPageFlush(current, end);
+#elif OS(QNX)
+#if !ENABLE(ASSEMBLER_WX_EXCLUSIVE)
+ msync(code, size, MS_INVALIDATE_ICACHE);
+#else
+ UNUSED_PARAM(code);
+ UNUSED_PARAM(size);
+#endif
#else
#error "The cacheFlush support is missing on this platform."
#endif
diff --git a/src/3rdparty/masm/wtf/MathExtras.h b/src/3rdparty/masm/wtf/MathExtras.h
index 3740d54beb..a529ba7b37 100644
--- a/src/3rdparty/masm/wtf/MathExtras.h
+++ b/src/3rdparty/masm/wtf/MathExtras.h
@@ -147,11 +147,6 @@ inline long lroundf(float num) { return static_cast<long>(roundf(num)); }
#endif
-#if COMPILER(GCC) && OS(QNX) && _CPPLIB_VER < 640
-// The stdlib on QNX < 6.6 doesn't contain long abs(long). See PR #104666.
-inline long long abs(long num) { return labs(num); }
-#endif
-
#if COMPILER(MSVC) && COMPILER(MSVC12_OR_LOWER)
// MSVC's math.h does not currently supply log2 or log2f.
inline double log2(double num)
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
index f191fe9679..9514204392 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
@@ -209,19 +209,32 @@ QVariant QQmlEngineDebugServiceImpl::valueContents(QVariant value) const
}
if (QQmlValueTypeFactory::isValueType(userType)) {
+ switch (userType) {
+ case QMetaType::QRect:
+ case QMetaType::QRectF:
+ case QMetaType::QPoint:
+ case QMetaType::QPointF:
+ case QMetaType::QSize:
+ case QMetaType::QSizeF:
+ case QMetaType::QFont:
+ // Don't call the toString() method on those. The stream operators are better.
+ return value;
+ default:
+ break;
+ }
+
const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(userType);
if (mo) {
- int toStringIndex = mo->indexOfMethod("toString");
+ int toStringIndex = mo->indexOfMethod("toString()");
if (toStringIndex != -1) {
QMetaMethod mm = mo->method(toStringIndex);
- QMetaType info(userType);
QString s;
- if (info.flags() & QMetaType::IsGadget
- && mm.invokeOnGadget(value.data(), Q_RETURN_ARG(QString, s)))
+ if (mm.invokeOnGadget(value.data(), Q_RETURN_ARG(QString, s)))
return s;
}
}
+ // We expect all QML value types to either have a toString() method or stream operators
return value;
}
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
index 0d69b2ab66..a2bc4c09a3 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
@@ -296,10 +296,11 @@ void QQmlProfilerServiceImpl::stopProfiling(QJSEngine *engine)
for (QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin());
i != m_engineProfilers.end(); ++i) {
if (i.value()->isRunning()) {
+ m_startTimes.insert(-1, i.value());
if (engine == 0 || i.key() == engine) {
- m_startTimes.insert(-1, i.value());
stopping << i.value();
} else {
+ reporting << i.value();
stillRunning = true;
}
}
@@ -369,25 +370,32 @@ void QQmlProfilerServiceImpl::sendMessages()
}
}
+ bool stillRunning = false;
+ for (const QQmlAbstractProfilerAdapter *profiler : qAsConst(m_engineProfilers)) {
+ if (profiler->isRunning()) {
+ stillRunning = true;
+ break;
+ }
+ }
+
if (m_waitingForStop) {
- //indicate completion
+ // EndTrace can be sent multiple times, as it's engine specific.
messages << traceEnd.data();
- QQmlDebugPacket ds;
- ds << static_cast<qint64>(-1) << static_cast<qint32>(Complete);
- messages << ds.data();
- m_waitingForStop = false;
+ if (!stillRunning) {
+ // Complete is only sent once, when no engines are running anymore.
+ QQmlDebugPacket ds;
+ ds << static_cast<qint64>(-1) << static_cast<qint32>(Complete);
+ messages << ds.data();
+ m_waitingForStop = false;
+ }
}
emit messagesToClient(name(), messages);
// Restart flushing if any profilers are still running
- for (const QQmlAbstractProfilerAdapter *profiler : qAsConst(m_engineProfilers)) {
- if (profiler->isRunning()) {
- emit startFlushTimer();
- break;
- }
- }
+ if (stillRunning)
+ emit startFlushTimer();
}
void QQmlProfilerServiceImpl::stateAboutToBeChanged(QQmlDebugService::State newState)
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index 1ac4925ed3..b726d2fc43 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -91,9 +91,8 @@ QQmlAnimationTimer *QQmlAnimationTimer::instance()
void QQmlAnimationTimer::ensureTimerUpdate()
{
- QQmlAnimationTimer *inst = QQmlAnimationTimer::instance(false);
QUnifiedTimer *instU = QUnifiedTimer::instance(false);
- if (instU && inst && inst->isPaused)
+ if (instU && isPaused)
instU->updateAnimationTimers(-1);
}
@@ -128,9 +127,7 @@ void QQmlAnimationTimer::updateAnimationsTime(qint64 delta)
void QQmlAnimationTimer::updateAnimationTimer()
{
- QQmlAnimationTimer *inst = QQmlAnimationTimer::instance(false);
- if (inst)
- inst->restartAnimationTimer();
+ restartAnimationTimer();
}
void QQmlAnimationTimer::restartAnimationTimer()
@@ -175,45 +172,38 @@ void QQmlAnimationTimer::registerAnimation(QAbstractAnimationJob *animation, boo
if (animation->userControlDisabled())
return;
- QQmlAnimationTimer *inst = instance(true); //we create the instance if needed
- inst->registerRunningAnimation(animation);
+ registerRunningAnimation(animation);
if (isTopLevel) {
Q_ASSERT(!animation->m_hasRegisteredTimer);
animation->m_hasRegisteredTimer = true;
- inst->animationsToStart << animation;
- if (!inst->startAnimationPending) {
- inst->startAnimationPending = true;
- QMetaObject::invokeMethod(inst, "startAnimations", Qt::QueuedConnection);
+ animationsToStart << animation;
+ if (!startAnimationPending) {
+ startAnimationPending = true;
+ QMetaObject::invokeMethod(this, "startAnimations", Qt::QueuedConnection);
}
}
}
void QQmlAnimationTimer::unregisterAnimation(QAbstractAnimationJob *animation)
{
- QQmlAnimationTimer *inst = QQmlAnimationTimer::instance(false);
- if (inst) {
- //at this point the unified timer should have been created
- //but it might also have been already destroyed in case the application is shutting down
+ unregisterRunningAnimation(animation);
- inst->unregisterRunningAnimation(animation);
-
- if (!animation->m_hasRegisteredTimer)
- return;
+ if (!animation->m_hasRegisteredTimer)
+ return;
- int idx = inst->animations.indexOf(animation);
- if (idx != -1) {
- inst->animations.removeAt(idx);
- // this is needed if we unregister an animation while its running
- if (idx <= inst->currentAnimationIdx)
- --inst->currentAnimationIdx;
+ int idx = animations.indexOf(animation);
+ if (idx != -1) {
+ animations.removeAt(idx);
+ // this is needed if we unregister an animation while its running
+ if (idx <= currentAnimationIdx)
+ --currentAnimationIdx;
- if (inst->animations.isEmpty() && !inst->stopTimerPending) {
- inst->stopTimerPending = true;
- QMetaObject::invokeMethod(inst, "stopTimer", Qt::QueuedConnection);
- }
- } else {
- inst->animationsToStart.removeOne(animation);
+ if (animations.isEmpty() && !stopTimerPending) {
+ stopTimerPending = true;
+ QMetaObject::invokeMethod(this, "stopTimer", Qt::QueuedConnection);
}
+ } else {
+ animationsToStart.removeOne(animation);
}
animation->m_hasRegisteredTimer = false;
}
@@ -302,8 +292,10 @@ QAbstractAnimationJob::~QAbstractAnimationJob()
stateChanged(oldState, m_state);
Q_ASSERT(m_state == Stopped);
- if (oldState == Running)
- QQmlAnimationTimer::unregisterAnimation(this);
+ if (oldState == Running) {
+ Q_ASSERT(QQmlAnimationTimer::instance() == m_timer);
+ m_timer->unregisterAnimation(this);
+ }
Q_ASSERT(!m_hasRegisteredTimer);
}
@@ -327,6 +319,9 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
if (m_loopCount == 0)
return;
+ if (!m_timer)
+ m_timer = QQmlAnimationTimer::instance();
+
State oldState = m_state;
int oldCurrentTime = m_currentTime;
int oldCurrentLoop = m_currentLoop;
@@ -352,11 +347,11 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
bool isTopLevel = !m_group || m_group->isStopped();
if (oldState == Running) {
if (newState == Paused && m_hasRegisteredTimer)
- QQmlAnimationTimer::ensureTimerUpdate();
+ m_timer->ensureTimerUpdate();
//the animation, is not running any more
- QQmlAnimationTimer::unregisterAnimation(this);
+ m_timer->unregisterAnimation(this);
} else if (newState == Running) {
- QQmlAnimationTimer::registerAnimation(this, isTopLevel);
+ m_timer->registerAnimation(this, isTopLevel);
}
//starting an animation qualifies as a top level loop change
@@ -383,7 +378,7 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
m_currentLoop = 0;
if (isTopLevel) {
// currentTime needs to be updated if pauseTimer is active
- RETURN_IF_DELETED(QQmlAnimationTimer::ensureTimerUpdate());
+ RETURN_IF_DELETED(m_timer->ensureTimerUpdate());
RETURN_IF_DELETED(setCurrentTime(m_totalCurrentTime));
}
}
@@ -420,14 +415,14 @@ void QAbstractAnimationJob::setDirection(Direction direction)
// the commands order below is important: first we need to setCurrentTime with the old direction,
// then update the direction on this and all children and finally restart the pauseTimer if needed
if (m_hasRegisteredTimer)
- QQmlAnimationTimer::ensureTimerUpdate();
+ m_timer->ensureTimerUpdate();
m_direction = direction;
updateDirection(direction);
if (m_hasRegisteredTimer)
// needed to update the timer interval in case of a pause animation
- QQmlAnimationTimer::updateAnimationTimer();
+ m_timer->updateAnimationTimer();
}
void QAbstractAnimationJob::setLoopCount(int loopCount)
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index 95a39b1301..63fd4b0dac 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -60,6 +60,8 @@ QT_BEGIN_NAMESPACE
class QAnimationGroupJob;
class QAnimationJobChangeListener;
+class QQmlAnimationTimer;
+
class Q_QML_PRIVATE_EXPORT QAbstractAnimationJob
{
Q_DISABLE_COPY(QAbstractAnimationJob)
@@ -168,6 +170,7 @@ protected:
QAbstractAnimationJob *m_nextSibling;
QAbstractAnimationJob *m_previousSibling;
+ QQmlAnimationTimer *m_timer = nullptr;
bool *m_wasDeleted;
bool m_hasRegisteredTimer:1;
@@ -203,20 +206,20 @@ public:
static QQmlAnimationTimer *instance();
static QQmlAnimationTimer *instance(bool create);
- static void registerAnimation(QAbstractAnimationJob *animation, bool isTopLevel);
- static void unregisterAnimation(QAbstractAnimationJob *animation);
+ void registerAnimation(QAbstractAnimationJob *animation, bool isTopLevel);
+ void unregisterAnimation(QAbstractAnimationJob *animation);
/*
this is used for updating the currentTime of all animations in case the pause
timer is active or, otherwise, only of the animation passed as parameter.
*/
- static void ensureTimerUpdate();
+ void ensureTimerUpdate();
/*
this will evaluate the need of restarting the pause timer in case there is still
some pause animations running.
*/
- static void updateAnimationTimer();
+ void updateAnimationTimer();
void restartAnimationTimer() override;
void updateAnimationsTime(qint64 timeStep) override;
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 128eb2c720..c95f8ad344 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1770,7 +1770,8 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding
JSCodeGen::JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
QV4::Compiler::Module *jsModule, QQmlJS::Engine *jsEngine,
- QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool)
+ QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports,
+ const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames)
: QV4::Compiler::Codegen(jsUnitGenerator, /*strict mode*/false)
, sourceCode(sourceCode)
, jsEngine(jsEngine)
@@ -1782,6 +1783,7 @@ JSCodeGen::JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *
, _scopeObject(0)
, _qmlContextSlot(-1)
, _importedScriptsSlot(-1)
+ , m_globalNames(globalNames)
{
_module = jsModule;
_fileNameIsUrl = true;
@@ -2241,6 +2243,12 @@ QV4::Compiler::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &n
return Reference::fromQmlContextObject(base, data->coreIndex(), data->notifyIndex(),
captureRequired);
}
+
+ if (m_globalNames.contains(name)) {
+ Reference r = Reference::fromName(this, name);
+ r.global = true;
+ return r;
+ }
#else
Q_UNUSED(name)
#endif // V4_BOOTSTRAP
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 406c939998..f8f8649fc7 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -610,8 +610,8 @@ struct Q_QML_EXPORT PropertyResolver
struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
{
JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator, QV4::Compiler::Module *jsModule,
- QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports,
- const QV4::Compiler::StringTableGenerator *stringPool);
+ QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot,
+ QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames);
struct IdMapping
{
@@ -651,6 +651,7 @@ private:
QQmlPropertyCache *_scopeObject;
int _qmlContextSlot;
int _importedScriptsSlot;
+ QSet<QString> m_globalNames;
};
struct Q_QML_PRIVATE_EXPORT IRLoader {
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 836aa8c416..061edb3dcf 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -139,10 +139,11 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
sss.scan();
}
- document->jsModule.fileName = typeData->finalUrlString();
- QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine, document->program, typeNameCache, &document->jsGenerator.stringTable);
+ document->jsModule.fileName = typeData->urlString();
+ document->jsModule.finalUrl = typeData->finalUrlString();
+ QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine,
+ document->program, typeNameCache, &document->jsGenerator.stringTable, engine->v8engine()->illegalNames());
v4CodeGenerator.setUseFastLookups(false);
- // ### v4CodeGenerator.setUseTypeInference(true);
QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
if (!jsCodeGen.generateCodeForComponents())
return nullptr;
@@ -1092,7 +1093,11 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv
alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
} else {
QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
- Q_ASSERT(targetCache);
+ if (!targetCache) {
+ *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
+ break;
+ }
+
QmlIR::PropertyResolver resolver(targetCache);
QQmlPropertyData *targetProperty = resolver.property(property.toString());
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index ae6557968b..677032bb2b 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -102,6 +102,7 @@ Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict)
}
void Codegen::generateFromProgram(const QString &fileName,
+ const QString &finalUrl,
const QString &sourceCode,
Program *node,
Module *module,
@@ -112,7 +113,9 @@ void Codegen::generateFromProgram(const QString &fileName,
_module = module;
_context = 0;
+ // ### should be set on the module outside of this method
_module->fileName = fileName;
+ _module->finalUrl = finalUrl;
ScanFunctions scan(this, sourceCode, mode);
scan(node);
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index dba9388292..5c4ce14870 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -97,6 +97,7 @@ public:
void generateFromProgram(const QString &fileName,
+ const QString &finalUrl,
const QString &sourceCode,
AST::Program *ast,
Module *module,
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index cdba3a5931..86cdb3eade 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -448,6 +448,7 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
if (jsUnit->sourceFileIndex == quint32(0) || jsUnit->stringAt(jsUnit->sourceFileIndex) != irDocument->jsModule.fileName) {
ensureWritableUnit();
jsUnit->sourceFileIndex = stringTable.registerString(irDocument->jsModule.fileName);
+ jsUnit->finalUrlIndex = stringTable.registerString(irDocument->jsModule.finalUrl);
}
// Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example)
@@ -692,7 +693,7 @@ static QByteArray ownLibraryChecksum()
// the cache files may end up being re-used. To avoid that we also add the checksum of
// the QtQml library.
Dl_info libInfo;
- if (dladdr(reinterpret_cast<const void *>(&ownLibraryChecksum), &libInfo) != 0) {
+ if (dladdr(reinterpret_cast<void *>(&ownLibraryChecksum), &libInfo) != 0) {
QFile library(QFile::decodeName(libInfo.dli_fname));
if (library.open(QIODevice::ReadOnly)) {
QCryptographicHash hash(QCryptographicHash::Md5);
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 359a92c166..2c0320f7f1 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -72,7 +72,7 @@
QT_BEGIN_NAMESPACE
// Bump this whenever the compiler data structures change in an incompatible way.
-#define QV4_DATA_STRUCTURE_VERSION 0x16
+#define QV4_DATA_STRUCTURE_VERSION 0x17
class QIODevice;
class QQmlPropertyCache;
@@ -717,6 +717,7 @@ struct Unit
quint32_le offsetToJSClassTable;
qint32_le indexOfRootFunction;
quint32_le sourceFileIndex;
+ quint32_le finalUrlIndex;
/* QML specific fields */
quint32_le nImports;
@@ -724,6 +725,8 @@ struct Unit
quint32_le nObjects;
quint32_le offsetToObjects;
+ quint32_le padding;
+
const Import *importAt(int idx) const {
return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
}
@@ -788,7 +791,7 @@ struct Unit
}
};
-static_assert(sizeof(Unit) == 136, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+static_assert(sizeof(Unit) == 144, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct TypeReference
{
@@ -918,13 +921,28 @@ public:
ExecutionEngine *engine = nullptr;
QQmlEnginePrivate *qmlEngine = nullptr; // only used in QML environment for composite types, not in plain QJSEngine case.
+ // url() and fileName() shall be used to load the actual QML/JS code or to show errors or
+ // warnings about that code. They include any potential URL interceptions and thus represent the
+ // "physical" location of the code.
+ //
+ // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code
+ // They are _not_ intercepted and thus represent the "logical" name for the code.
+
QString fileName() const { return data->stringAt(data->sourceFileIndex); }
+ QString finalUrlString() const { return data->stringAt(data->finalUrlIndex); }
QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
+ QUrl finalUrl() const
+ {
+ if (m_finalUrl.isNull)
+ m_finalUrl = QUrl(finalUrlString());
+ return m_finalUrl;
+ }
QV4::Lookup *runtimeLookups = nullptr;
QV4::InternalClass **runtimeClasses = nullptr;
QVector<QV4::Function *> runtimeFunctions;
mutable QQmlNullableValue<QUrl> m_url;
+ mutable QQmlNullableValue<QUrl> m_finalUrl;
// QML specific fields
QQmlPropertyCacheVector propertyCaches;
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 3be34720fa..f2e1f4a0de 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -222,6 +222,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, CompiledData::JSC
QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
{
registerString(module->fileName);
+ registerString(module->finalUrl);
for (Context *f : qAsConst(module->functions)) {
registerString(f->name);
for (int i = 0; i < f->arguments.size(); ++i)
@@ -446,6 +447,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
}
unit.indexOfRootFunction = -1;
unit.sourceFileIndex = getStringId(module->fileName);
+ unit.finalUrlIndex = getStringId(module->finalUrl);
unit.sourceTimeStamp = module->sourceTimeStamp.isValid() ? module->sourceTimeStamp.toMSecsSinceEpoch() : 0;
unit.nImports = 0;
unit.offsetToImports = 0;
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 52a4bb9159..bd68ea513e 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -92,6 +92,7 @@ struct Module {
QList<Context *> functions;
Context *rootContext;
QString fileName;
+ QString finalUrl;
QDateTime sourceTimeStamp;
uint unitFlags = 0; // flags merged into CompiledData::Unit::flags
bool debugMode = false;
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index 7800b24076..2e87f10302 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -298,9 +298,10 @@ public:
{
// Use the QV4::Function as ID, as that is common among different instances of the same
// component. QQmlBinding is per instance.
- // Add 1 to the ID, to make it different from the IDs the V4 profiler produces. The +1 makes
- // the pointer point into the middle of the QV4::Function. Thus it still points to valid
- // memory but we cannot accidentally create a duplicate key from another object.
+ // Add 1 to the ID, to make it different from the IDs the V4 and signal handling profilers
+ // produce. The +1 makes the pointer point into the middle of the QV4::Function. Thus it
+ // still points to valid memory but we cannot accidentally create a duplicate key from
+ // another object.
// If there is no function, use a static but valid address: The profiler itself.
quintptr locationId = function ? id(function) + 1 : id(this);
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
@@ -332,7 +333,12 @@ public:
void startHandlingSignal(QQmlBoundSignalExpression *expression)
{
- quintptr locationId(id(expression));
+ // Use the QV4::Function as ID, as that is common among different instances of the same
+ // component. QQmlBoundSignalExpression is per instance.
+ // Add 2 to the ID, to make it different from the IDs the V4 and binding profilers produce.
+ // The +2 makes the pointer point into the middle of the QV4::Function. Thus it still points
+ // to valid memory but we cannot accidentally create a duplicate key from another object.
+ quintptr locationId(id(expression->function()) + 2);
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation), HandlingSignal,
locationId));
@@ -515,7 +521,12 @@ private:
QQmlProfiler *profiler;
};
+#endif // QT_NO_QML_DEBUGGER
+
QT_END_NAMESPACE
+
+#ifndef QT_NO_QML_DEBUGGER
+
Q_DECLARE_METATYPE(QVector<QQmlProfilerData>)
Q_DECLARE_METATYPE(QQmlProfiler::LocationHash)
diff --git a/src/qml/doc/src/includes/qqmlcomponent.qdoc b/src/qml/doc/src/includes/qqmlcomponent.qdoc
new file mode 100644
index 0000000000..0eb60ed743
--- /dev/null
+++ b/src/qml/doc/src/includes/qqmlcomponent.qdoc
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [url-note]
+Ensure that the URL provided is full and correct, in particular, use
+\l QUrl::fromLocalFile() when loading a file from the local filesystem.
+
+Relative paths will be resolved against the engine's
+\l {QQmlEngine::baseUrl}{baseUrl()}, which is the current working directory
+unless specified.
+//! [url-note]
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
index 207fb53ca0..31650db7c0 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
@@ -449,13 +449,38 @@ right-hand-side of the property declaration must be a valid alias reference:
[default] property alias <name>: <alias reference>
\endcode
-Unlike an ordinary property, an alias can only refer to an object, or the
-property of an object, that is within the scope of the \l{QML Object Types}
-{type} within which the alias is declared. It cannot contain arbitrary
-JavaScript expressions and it cannot refer to objects declared outside of
-the scope of its type. Also note the \e {alias reference} is not optional,
-unlike the optional default value for an ordinary property; the alias reference
-must be provided when the alias is first declared.
+Unlike an ordinary property, an alias has the following restrictions:
+
+\list
+\li It can only refer to an object, or the
+ property of an object, that is within the scope of the \l{QML Object Types}
+ {type} within which the alias is declared.
+\li It cannot contain arbitrary
+ JavaScript expressions
+\li It cannot refer to objects declared outside of
+ the scope of its type.
+\li The \e {alias reference} is not optional,
+ unlike the optional default value for an ordinary property; the alias reference
+ must be provided when the alias is first declared.
+\li It cannot refer to grouped properties; the following code will not work:
+ \code
+ property alias color: rectangle.border.color
+
+ Rectangle {
+ id: rectangle
+ }
+ \endcode
+
+ However, aliases to \l {QML Basic Types}{value type} properties do work:
+ \code
+ property alias rectX: object.rectProperty.x
+
+ Item {
+ id: object
+ property rect rectProperty
+ }
+ \endcode
+\endlist
For example, below is a \c Button type with a \c buttonText aliased property
which is connected to the \c text object of the \l Text child:
diff --git a/src/qml/doc/src/qtqml.qdoc b/src/qml/doc/src/qtqml.qdoc
index 833436a67c..a9f8e2a960 100644
--- a/src/qml/doc/src/qtqml.qdoc
+++ b/src/qml/doc/src/qtqml.qdoc
@@ -134,12 +134,13 @@ the QML code to interact with C++ code.
\section1 Licenses and Attributions
Qt QML is available under commercial licenses from \l{The Qt Company}.
-In addition, it is available under the
+In addition, it is available under free software licenses. Since Qt 5.4,
+these free software licenses are
\l{GNU Lesser General Public License, version 3}, or
the \l{GNU General Public License, version 2}.
See \l{Qt Licensing} for further details.
-Furthermore Qt QML potentially contains third party
+Furthermore Qt QML in Qt \QtVersion may contain third party
modules under following permissive licenses:
\generatelist{groupsbymodule attributions-qtqml}
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 167a40bc51..b9c06d6569 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -197,6 +197,7 @@ ExecutionEngine::ExecutionEngine()
internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable());
internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable());
+ internalClasses[Class_QmlContext] = internalClasses[EngineBase::Class_ExecutionContext]->changeVTable(QV4::QmlContext::staticVTable());
internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
jsStrings[String_Empty] = newIdentifier(QString());
@@ -239,6 +240,7 @@ ExecutionEngine::ExecutionEngine()
InternalClass *ic = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable());
jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic);
internalClasses[Class_Object] = ic->changePrototype(objectPrototype()->d());
+ internalClasses[EngineBase::Class_QmlContextWrapper] = internalClasses[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable());
ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype());
Q_ASSERT(ic->prototype);
@@ -875,14 +877,14 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
CppStackFrame *f = currentStackFrame;
while (f) {
if (f->v4Function) {
- base.setUrl(f->v4Function->sourceFile());
+ base = f->v4Function->finalUrl();
break;
}
f = f->parent;
}
if (base.isEmpty() && globalCode)
- base.setUrl(globalCode->sourceFile());
+ base = globalCode->finalUrl();
if (base.isEmpty())
return src;
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index 4f2e15fa93..59fb4a564a 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -110,6 +110,8 @@ struct Q_QML_EXPORT EngineBase {
Class_ErrorObject,
Class_ErrorObjectWithMessage,
Class_ErrorProto,
+ Class_QmlContextWrapper,
+ Class_QmlContext,
NClasses
};
InternalClass *internalClasses[NClasses];
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index dcbd41f2e6..4c8c790ca7 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -96,6 +96,7 @@ struct Q_QML_EXPORT Function {
return compilationUnit->runtimeStrings[compiledFunction->nameIndex];
}
inline QString sourceFile() const { return compilationUnit->fileName(); }
+ inline QUrl finalUrl() const { return compilationUnit->finalUrl(); }
inline bool usesArgumentsObject() const { return compiledFunction->flags & CompiledData::Function::UsesArgumentsObject; }
inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 244d1f89f3..7f82a02ae0 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -92,7 +92,7 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
&& (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD))
# define V4_ENABLE_JIT
#elif defined(Q_PROCESSOR_X86_64) && (QT_POINTER_SIZE == 8) \
- && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD))
+ && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD))
# define V4_ENABLE_JIT
#elif defined(Q_PROCESSOR_ARM_32) && (QT_POINTER_SIZE == 4)
# if defined(thumb2) || defined(__thumb2__) || ((defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4)
@@ -101,7 +101,7 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
# define V4_ENABLE_JIT
# endif
#elif defined(Q_PROCESSOR_ARM_64) && (QT_POINTER_SIZE == 8)
-# if defined(Q_OS_LINUX)
+# if defined(Q_OS_LINUX) || defined(Q_OS_QNX)
# define V4_ENABLE_JIT
# endif
//#elif defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX)
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index a1df5cb95f..647bef7fc1 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -91,6 +91,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object
{
V4_OBJECT2(QQmlContextWrapper, Object)
V4_NEEDS_DESTROY
+ V4_INTERNALCLASS(QmlContextWrapper)
inline QObject *getScopeObject() const { return d()->scopeObject; }
inline QQmlContextData *getContext() const { return *d()->context; }
@@ -104,6 +105,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object
struct Q_QML_EXPORT QmlContext : public ExecutionContext
{
V4_MANAGED(QmlContext, ExecutionContext)
+ V4_INTERNALCLASS(QmlContext)
static Heap::QmlContext *createWorkerContext(QV4::ExecutionContext *parent, const QUrl &source, Value *sendFunction);
static Heap::QmlContext *create(QV4::ExecutionContext *parent, QQmlContextData *context, QObject *scopeObject);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 56d9234be8..948dcdb24d 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -715,6 +715,10 @@ bool QObjectWrapper::put(Managed *m, String *name, const Value &value)
PropertyAttributes QObjectWrapper::query(const Managed *m, String *name)
{
const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m);
+ const QObject *thatObject = that->d()->object();
+ if (QQmlData::wasDeleted(thatObject))
+ return QV4::Object::query(m, name);
+
ExecutionEngine *engine = that->engine();
QQmlContextData *qmlContext = engine->callingQmlContext();
QQmlPropertyData local;
@@ -2083,10 +2087,10 @@ ReturnedValue QMetaObjectWrapper::callOverloadedConstructor(QV4::ExecutionEngine
for (int i = 0; i < numberOfConstructors; i++) {
const QQmlPropertyData & attempt = d()->constructors[i];
+ QQmlMetaObject::ArgTypeStorage storage;
int methodArgumentCount = 0;
int *methodArgTypes = 0;
if (attempt.hasArguments()) {
- QQmlMetaObject::ArgTypeStorage storage;
int *args = object.constructorParameterTypes(attempt.coreIndex(), &storage, 0);
if (!args) // Must be an unknown argument
continue;
diff --git a/src/qml/jsruntime/qv4runtimecodegen.cpp b/src/qml/jsruntime/qv4runtimecodegen.cpp
index 9c115099b5..662a780e71 100644
--- a/src/qml/jsruntime/qv4runtimecodegen.cpp
+++ b/src/qml/jsruntime/qv4runtimecodegen.cpp
@@ -49,6 +49,7 @@ void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName,
{
_module = module;
_module->fileName = fileName;
+ _module->finalUrl = fileName;
_context = 0;
Compiler::ScanFunctions scan(this, sourceCode, Compiler::GlobalCode);
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index e0c0c2d403..0c5f02bcfc 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -121,7 +121,7 @@ void Script::parse()
RuntimeCodegen cg(v4, &jsGenerator, strictMode);
if (inheritContext)
cg.setUseFastLookups(false);
- cg.generateFromProgram(sourceFile, sourceCode, program, &module, compilationMode);
+ cg.generateFromProgram(sourceFile, sourceFile, sourceCode, program, &module, compilationMode);
if (v4->hasException)
return;
@@ -164,8 +164,8 @@ Function *Script::function()
}
QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator,
- const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors,
- Directives *directivesCollector)
+ const QString &fileName, const QString &finalUrl, const QString &source,
+ QList<QQmlError> *reportedErrors, Directives *directivesCollector)
{
using namespace QV4::Compiler;
using namespace QQmlJS::AST;
@@ -184,12 +184,12 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compi
const auto diagnosticMessages = parser.diagnosticMessages();
for (const DiagnosticMessage &m : diagnosticMessages) {
if (m.isWarning()) {
- qWarning("%s:%d : %s", qPrintable(url.toString()), m.loc.startLine, qPrintable(m.message));
+ qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message));
continue;
}
QQmlError error;
- error.setUrl(url);
+ error.setUrl(QUrl(fileName));
error.setDescription(m.message);
error.setLine(m.loc.startLine);
error.setColumn(m.loc.startColumn);
@@ -211,7 +211,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compi
Codegen cg(unitGenerator, /*strict mode*/false);
cg.setUseFastLookups(false);
- cg.generateFromProgram(url.toString(), source, program, module, GlobalCode);
+ cg.generateFromProgram(fileName, finalUrl, source, program, module, GlobalCode);
errors = cg.qmlErrors();
if (!errors.isEmpty()) {
if (reportedErrors)
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index e6b60105f7..6ba405f828 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -97,8 +97,10 @@ struct Q_QML_EXPORT Script {
Function *function();
- static QQmlRefPointer<CompiledData::CompilationUnit> precompile(QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator, const QUrl &url, const QString &source,
- QList<QQmlError> *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0);
+ static QQmlRefPointer<CompiledData::CompilationUnit> precompile(
+ QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator,
+ const QString &fileName, const QString &finalUrl, const QString &source,
+ QList<QQmlError> *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0);
static Script *createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl);
static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext);
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 08d7228ee9..4a0c12b9da 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -44,6 +44,7 @@
#include "qv4qobjectwrapper_p.h"
#include <QtCore/qalgorithms.h>
#include <QtCore/private/qnumeric_p.h>
+#include <QtCore/qloggingcategory.h>
#include <qqmlengine.h>
#include "PageReservation.h"
#include "PageAllocation.h"
@@ -91,6 +92,11 @@
#define MIN_UNMANAGED_HEAPSIZE_GC_LIMIT std::size_t(128 * 1024)
+Q_LOGGING_CATEGORY(lcGcStats, "qt.qml.gc.statistics")
+Q_DECLARE_LOGGING_CATEGORY(lcGcStats)
+Q_LOGGING_CATEGORY(lcGcAllocatorStats, "qt.qml.gc.allocatorStats")
+Q_DECLARE_LOGGING_CATEGORY(lcGcAllocatorStats)
+
using namespace WTF;
QT_BEGIN_NAMESPACE
@@ -504,9 +510,9 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
Q_ASSERT((size % Chunk::SlotSize) == 0);
size_t slotsRequired = size >> Chunk::SlotSizeShift;
-#if MM_DEBUG
- ++allocations[bin];
-#endif
+
+ if (allocationStats)
+ ++allocationStats[binForSlots(slotsRequired)];
HeapItem **last;
@@ -648,37 +654,6 @@ void BlockAllocator::collectGrayItems(MarkStack *markStack)
}
-#if MM_DEBUG
-void BlockAllocator::stats() {
- DEBUG << "MM stats:";
- QString s;
- for (int i = 0; i < 10; ++i) {
- uint c = 0;
- HeapItem *item = freeBins[i];
- while (item) {
- ++c;
- item = item->freeData.next;
- }
- s += QString::number(c) + QLatin1String(", ");
- }
- HeapItem *item = freeBins[NumBins - 1];
- uint c = 0;
- while (item) {
- ++c;
- item = item->freeData.next;
- }
- s += QLatin1String("..., ") + QString::number(c);
- DEBUG << "bins:" << s;
- QString a;
- for (int i = 0; i < 10; ++i)
- a += QString::number(allocations[i]) + QLatin1String(", ");
- a += QLatin1String("..., ") + QString::number(allocations[NumBins - 1]);
- DEBUG << "allocs:" << a;
- memset(allocations, 0, sizeof(allocations));
-}
-#endif
-
-
HeapItem *HugeItemAllocator::allocate(size_t size) {
Chunk *c = chunkAllocator->allocate(size);
chunks.push_back(HugeChunk{c, size});
@@ -754,11 +729,15 @@ MemoryManager::MemoryManager(ExecutionEngine *engine)
, m_weakValues(new PersistentValueStorage(engine))
, unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT)
, aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
- , gcStats(!qEnvironmentVariableIsEmpty(QV4_MM_STATS))
+ , gcStats(lcGcStats().isDebugEnabled())
+ , gcCollectorStats(lcGcAllocatorStats().isDebugEnabled())
{
#ifdef V4_USE_VALGRIND
VALGRIND_CREATE_MEMPOOL(this, 0, true);
#endif
+ memset(statistics.allocations, 0, sizeof(statistics.allocations));
+ if (gcStats)
+ blockAllocator.allocationStats = statistics.allocations;
}
#ifdef MM_STATS
@@ -818,9 +797,6 @@ Heap::Base *MemoryManager::allocData(std::size_t size)
runGC();
didRunGC = true;
}
-#ifdef DETAILED_MM_STATS
- willAllocate(size);
-#endif // DETAILED_MM_STATS
Q_ASSERT(size >= Chunk::SlotSize);
Q_ASSERT(size % Chunk::SlotSize == 0);
@@ -1021,9 +997,10 @@ bool MemoryManager::shouldRunGC() const
size_t dumpBins(BlockAllocator *b, bool printOutput = true)
{
+ const QLoggingCategory &stats = lcGcAllocatorStats();
size_t totalSlotMem = 0;
if (printOutput)
- qDebug() << "Slot map:";
+ qDebug(stats) << "Slot map:";
for (uint i = 0; i < BlockAllocator::NumBins; ++i) {
uint nEntries = 0;
HeapItem *h = b->freeBins[i];
@@ -1033,7 +1010,7 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true)
h = h->freeData.next;
}
if (printOutput)
- qDebug() << " number of entries in slot" << i << ":" << nEntries;
+ qDebug(stats) << " number of entries in slot" << i << ":" << nEntries;
}
SDUMP() << " large slot map";
HeapItem *h = b->freeBins[BlockAllocator::NumBins - 1];
@@ -1043,7 +1020,7 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true)
}
if (printOutput)
- qDebug() << " total mem in bins" << totalSlotMem*Chunk::SlotSize;
+ qDebug(stats) << " total mem in bins" << totalSlotMem*Chunk::SlotSize;
return totalSlotMem*Chunk::SlotSize;
}
@@ -1057,27 +1034,32 @@ void MemoryManager::runGC()
QScopedValueRollback<bool> gcBlocker(gcBlocked, true);
// qDebug() << "runGC";
- if (!gcStats) {
-// uint oldUsed = allocator.usedMem();
+ if (gcStats) {
+ statistics.maxReservedMem = qMax(statistics.maxReservedMem, getAllocatedMem());
+ statistics.maxAllocatedMem = qMax(statistics.maxAllocatedMem, getUsedMem() + getLargeItemsMem());
+ }
+
+ if (!gcCollectorStats) {
mark();
sweep();
-// DEBUG << "RUN GC: allocated:" << allocator.allocatedMem() << "used before" << oldUsed << "used now" << allocator.usedMem();
} else {
bool triggeredByUnmanagedHeap = (unmanagedHeapSize > unmanagedHeapSizeGCLimit);
size_t oldUnmanagedSize = unmanagedHeapSize;
+
const size_t totalMem = getAllocatedMem();
const size_t usedBefore = getUsedMem();
const size_t largeItemsBefore = getLargeItemsMem();
- qDebug() << "========== GC ==========";
+ const QLoggingCategory &stats = lcGcAllocatorStats();
+ qDebug(stats) << "========== GC ==========";
#ifdef MM_STATS
- qDebug() << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots.";
- qDebug() << " Allocations since last GC" << allocationCount;
+ qDebug(stats) << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots.";
+ qDebug(stats) << " Allocations since last GC" << allocationCount;
allocationCount = 0;
#endif
size_t oldChunks = blockAllocator.chunks.size();
- qDebug() << "Allocated" << totalMem << "bytes in" << oldChunks << "chunks";
- qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore);
+ qDebug(stats) << "Allocated" << totalMem << "bytes in" << oldChunks << "chunks";
+ qDebug(stats) << "Fragmented memory before GC" << (totalMem - usedBefore);
dumpBins(&blockAllocator);
#ifdef MM_STATS
@@ -1095,15 +1077,15 @@ void MemoryManager::runGC()
qint64 sweepTime = t.nsecsElapsed()/1000;
if (triggeredByUnmanagedHeap) {
- qDebug() << "triggered by unmanaged heap:";
- qDebug() << " old unmanaged heap size:" << oldUnmanagedSize;
- qDebug() << " new unmanaged heap:" << unmanagedHeapSize;
- qDebug() << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit;
+ qDebug(stats) << "triggered by unmanaged heap:";
+ qDebug(stats) << " old unmanaged heap size:" << oldUnmanagedSize;
+ qDebug(stats) << " new unmanaged heap:" << unmanagedHeapSize;
+ qDebug(stats) << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit;
}
size_t memInBins = dumpBins(&blockAllocator);
- qDebug() << "Marked object in" << markTime << "us.";
- qDebug() << " " << markStackSize << "objects marked";
- qDebug() << "Sweeped object in" << sweepTime << "us.";
+ qDebug(stats) << "Marked object in" << markTime << "us.";
+ qDebug(stats) << " " << markStackSize << "objects marked";
+ qDebug(stats) << "Sweeped object in" << sweepTime << "us.";
// sort our object types by number of freed instances
MMStatsHash freedObjectStats;
@@ -1118,26 +1100,29 @@ void MemoryManager::runGC()
return a.second > b.second && strcmp(a.first, b.first) < 0;
});
- qDebug() << "Used memory before GC:" << usedBefore;
- qDebug() << "Used memory after GC:" << usedAfter;
- qDebug() << "Freed up bytes :" << (usedBefore - usedAfter);
- qDebug() << "Freed up chunks :" << (oldChunks - blockAllocator.chunks.size());
+ qDebug(stats) << "Used memory before GC:" << usedBefore;
+ qDebug(stats) << "Used memory after GC:" << usedAfter;
+ qDebug(stats) << "Freed up bytes :" << (usedBefore - usedAfter);
+ qDebug(stats) << "Freed up chunks :" << (oldChunks - blockAllocator.chunks.size());
size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter;
if (lost)
- qDebug() << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
+ qDebug(stats) << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
if (largeItemsBefore || largeItemsAfter) {
- qDebug() << "Large item memory before GC:" << largeItemsBefore;
- qDebug() << "Large item memory after GC:" << largeItemsAfter;
- qDebug() << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter);
+ qDebug(stats) << "Large item memory before GC:" << largeItemsBefore;
+ qDebug(stats) << "Large item memory after GC:" << largeItemsAfter;
+ qDebug(stats) << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter);
}
for (auto it = freedObjectsSorted.cbegin(); it != freedObjectsSorted.cend(); ++it) {
- qDebug().noquote() << QString::fromLatin1("Freed JS type: %1 (%2 instances)").arg(QString::fromLatin1(it->first), QString::number(it->second));
+ qDebug(stats).noquote() << QString::fromLatin1("Freed JS type: %1 (%2 instances)").arg(QString::fromLatin1(it->first), QString::number(it->second));
}
- qDebug() << "======== End GC ========";
+ qDebug(stats) << "======== End GC ========";
}
+ if (gcStats)
+ statistics.maxUsedMem = qMax(statistics.maxUsedMem, getUsedMem() + getLargeItemsMem());
+
if (aggressiveGC) {
// ensure we don't 'loose' any memory
Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false));
@@ -1169,6 +1154,8 @@ MemoryManager::~MemoryManager()
{
delete m_persistentValues;
+ dumpStats();
+
sweep(/*lastSweep*/true);
blockAllocator.freeAll();
hugeItemAllocator.freeAll();
@@ -1183,30 +1170,20 @@ MemoryManager::~MemoryManager()
void MemoryManager::dumpStats() const
{
-#ifdef DETAILED_MM_STATS
- std::cerr << "=================" << std::endl;
- std::cerr << "Allocation stats:" << std::endl;
- std::cerr << "Requests for each chunk size:" << std::endl;
- for (int i = 0; i < allocSizeCounters.size(); ++i) {
- if (unsigned count = allocSizeCounters[i]) {
- std::cerr << "\t" << (i << 4) << " bytes chunks: " << count << std::endl;
- }
- }
-#endif // DETAILED_MM_STATS
-}
+ if (!gcStats)
+ return;
-#ifdef DETAILED_MM_STATS
-void MemoryManager::willAllocate(std::size_t size)
-{
- unsigned alignedSize = (size + 15) >> 4;
- QVector<unsigned> &counters = allocSizeCounters;
- if ((unsigned) counters.size() < alignedSize + 1)
- counters.resize(alignedSize + 1);
- counters[alignedSize]++;
+ const QLoggingCategory &stats = lcGcStats();
+ qDebug(stats) << "Qml GC memory allocation statistics:";
+ qDebug(stats) << "Total memory allocated:" << statistics.maxReservedMem;
+ qDebug(stats) << "Max memory used before a GC run:" << statistics.maxAllocatedMem;
+ qDebug(stats) << "Max memory used after a GC run:" << statistics.maxUsedMem;
+ qDebug(stats) << "Requests for different item sizes:";
+ for (int i = 1; i < BlockAllocator::NumBins - 1; ++i)
+ qDebug(stats) << " <" << (i << Chunk::SlotSizeShift) << " bytes: " << statistics.allocations[i];
+ qDebug(stats) << " >=" << ((BlockAllocator::NumBins - 1) << Chunk::SlotSizeShift) << " bytes: " << statistics.allocations[BlockAllocator::NumBins - 1];
}
-#endif // DETAILED_MM_STATS
-
void MemoryManager::collectFromJSStack(MarkStack *markStack) const
{
Value *v = engine->jsStackBase;
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 058cbe28cc..7dc73bdacc 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -58,8 +58,6 @@
#include <private/qv4mmdefs_p.h>
#include <QVector>
-//#define DETAILED_MM_STATS
-
#define QV4_MM_MAXBLOCK_SHIFT "QV4_MM_MAXBLOCK_SHIFT"
#define QV4_MM_MAX_CHUNK_SIZE "QV4_MM_MAX_CHUNK_SIZE"
#define QV4_MM_STATS "QV4_MM_STATS"
@@ -77,9 +75,6 @@ struct BlockAllocator {
: chunkAllocator(chunkAllocator), engine(engine)
{
memset(freeBins, 0, sizeof(freeBins));
-#if MM_DEBUG
- memset(allocations, 0, sizeof(allocations));
-#endif
}
enum { NumBins = 8 };
@@ -88,10 +83,6 @@ struct BlockAllocator {
return nSlots >= NumBins ? NumBins - 1 : nSlots;
}
-#if MM_DEBUG
- void stats();
-#endif
-
HeapItem *allocate(size_t size, bool forceAllocation = false);
size_t totalSlots() const {
@@ -121,9 +112,7 @@ struct BlockAllocator {
ChunkAllocator *chunkAllocator;
ExecutionEngine *engine;
std::vector<Chunk *> chunks;
-#if MM_DEBUG
- uint allocations[NumBins];
-#endif
+ uint *allocationStats = nullptr;
};
struct HugeItemAllocator {
@@ -407,10 +396,6 @@ protected:
Heap::Base *allocData(std::size_t size);
Heap::Object *allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers);
-#ifdef DETAILED_MM_STATS
- void willAllocate(std::size_t size);
-#endif // DETAILED_MM_STATS
-
private:
void collectFromJSStack(MarkStack *markStack) const;
void mark();
@@ -434,6 +419,14 @@ public:
bool gcBlocked = false;
bool aggressiveGC = false;
bool gcStats = false;
+ bool gcCollectorStats = false;
+
+ struct {
+ size_t maxReservedMem = 0;
+ size_t maxAllocatedMem = 0;
+ size_t maxUsedMem = 0;
+ uint allocations[BlockAllocator::NumBins];
+ } statistics;
};
}
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index c13227d8fe..acaff08a29 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -6,7 +6,7 @@ qtConfig(qml-network): \
DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES
-win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000
+msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x66000000
win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS
win32:!winrt:LIBS += -lshell32
solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index e3dc3be81e..97e2019ef1 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -497,8 +497,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent)
Create a QQmlComponent from the given \a url and give it the
specified \a parent and \a engine.
- Ensure that the URL provided is full and correct, in particular, use
- \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+ \include qqmlcomponent.qdoc url-note
\sa loadUrl()
*/
@@ -512,8 +511,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *paren
specified \a parent and \a engine. If \a mode is \l Asynchronous,
the component will be loaded and compiled asynchronously.
- Ensure that the URL provided is full and correct, in particular, use
- \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+ \include qqmlcomponent.qdoc url-note
\sa loadUrl()
*/
@@ -549,7 +547,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
: QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
- const QUrl url = QDir::isAbsolutePath(fileName) ? QUrl::fromLocalFile(fileName) : d->engine->baseUrl().resolved(QUrl(fileName));
+ const QUrl url = QDir::isAbsolutePath(fileName) ? QUrl::fromLocalFile(fileName) : QUrl(fileName);
d->loadUrl(url, mode);
}
@@ -562,7 +560,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::CompiledData::CompilationU
Q_D(QQmlComponent);
d->compilationUnit = compilationUnit;
d->start = start;
- d->url = compilationUnit->url();
+ d->url = compilationUnit->finalUrl();
d->progress = 1.0;
}
@@ -609,8 +607,7 @@ QQmlContext *QQmlComponent::creationContext() const
/*!
Load the QQmlComponent from the provided \a url.
- Ensure that the URL provided is full and correct, in particular, use
- \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+ \include qqmlcomponent.qdoc url-note
*/
void QQmlComponent::loadUrl(const QUrl &url)
{
@@ -622,8 +619,7 @@ void QQmlComponent::loadUrl(const QUrl &url)
Load the QQmlComponent from the provided \a url.
If \a mode is \l Asynchronous, the component will be loaded and compiled asynchronously.
- Ensure that the URL provided is full and correct, in particular, use
- \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+ \include qqmlcomponent.qdoc url-note
*/
void QQmlComponent::loadUrl(const QUrl &url, QQmlComponent::CompilationMode mode)
{
@@ -636,11 +632,21 @@ void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::Compilatio
Q_Q(QQmlComponent);
clear();
- if ((newUrl.isRelative() && !newUrl.isEmpty())
- || newUrl.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
- url = engine->baseUrl().resolved(newUrl);
- else
+ if (newUrl.isRelative()) {
+ // The new URL is a relative URL like QUrl("main.qml").
+ url = engine->baseUrl().resolved(QUrl(newUrl.toString()));
+ } else if (engine->baseUrl().isLocalFile() && newUrl.isLocalFile() && !QDir::isAbsolutePath(newUrl.toLocalFile())) {
+ // The new URL is a file on disk but it's a relative path; e.g.:
+ // QUrl::fromLocalFile("main.qml") or QUrl("file:main.qml")
+ // We need to remove the scheme so that it becomes a relative URL with a relative path:
+ QUrl fixedUrl(newUrl);
+ fixedUrl.setScheme(QString());
+ // Then, turn it into an absolute URL with an absolute path by resolving it against the engine's baseUrl().
+ // This is a compatibility hack for QTBUG-58837.
+ url = engine->baseUrl().resolved(fixedUrl);
+ } else {
url = newUrl;
+ }
if (newUrl.isEmpty()) {
QQmlError error;
@@ -1074,7 +1080,6 @@ void QQmlComponentPrivate::incubateObject(
QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
incubatorPriv->compilationUnit = componentPriv->compilationUnit;
- incubatorPriv->compilationUnit->addref();
incubatorPriv->enginePriv = enginePriv;
incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext));
incubatorPriv->subComponentToCreate = componentPriv->start;
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 9d2e37a2ab..32b25344ae 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -852,14 +852,14 @@ QV4::IdentifierHash &QQmlContextData::detachedPropertyNames()
QUrl QQmlContextData::url() const
{
if (typeCompilationUnit)
- return typeCompilationUnit->url();
+ return typeCompilationUnit->finalUrl();
return baseUrl;
}
QString QQmlContextData::urlString() const
{
if (typeCompilationUnit)
- return typeCompilationUnit->fileName();
+ return typeCompilationUnit->finalUrlString();
return baseUrlString;
}
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 63994a392d..5794e6f0c5 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -156,18 +156,21 @@ public:
quint32 hasInterceptorMetaObject:1;
quint32 hasVMEMetaObject:1;
quint32 parentFrozen:1;
- quint32 dummy:22;
+ quint32 dummy:6;
// When bindingBitsSize < sizeof(ptr), we store the binding bit flags inside
// bindingBitsValue. When we need more than sizeof(ptr) bits, we allocated
// sufficient space and use bindingBits to point to it.
- int bindingBitsSize;
+ quint32 bindingBitsArraySize : 16;
typedef quintptr BindingBitsType;
+ enum {
+ BitsPerType = sizeof(BindingBitsType) * 8,
+ InlineBindingArraySize = 2
+ };
union {
BindingBitsType *bindingBits;
- BindingBitsType bindingBitsValue;
+ BindingBitsType bindingBitsValue[InlineBindingArraySize];
};
- enum { MaxInlineBits = sizeof(BindingBitsType) * 8 };
struct NotifyList {
quint64 connectionMask;
@@ -259,7 +262,7 @@ public:
bool hasExtendedData() const { return extendedData != 0; }
QHash<int, QObject *> *attachedProperties() const;
- static inline bool wasDeleted(QObject *);
+ static inline bool wasDeleted(const QObject *);
static void markAsDeleted(QObject *);
static void setQueuedForDeletion(QObject *);
@@ -275,6 +278,9 @@ public:
return createPropertyCache(engine, object);
}
+ Q_ALWAYS_INLINE static uint offsetForBit(int bit) { return static_cast<uint>(bit) / BitsPerType; }
+ Q_ALWAYS_INLINE static BindingBitsType bitFlagForBit(int bit) { return BindingBitsType(1) << (static_cast<uint>(bit) & (BitsPerType - 1)); }
+
private:
// For attachedProperties
mutable QQmlDataExtended *extendedData;
@@ -286,26 +292,25 @@ private:
Q_ALWAYS_INLINE bool hasBitSet(int bit) const
{
- if (bindingBitsSize <= bit)
+ uint offset = offsetForBit(bit);
+ if (bindingBitsArraySize <= offset)
return false;
- if (bindingBitsSize == MaxInlineBits)
- return bindingBitsValue & (BindingBitsType(1) << bit);
- else
- return bindingBits[bit / MaxInlineBits] & (BindingBitsType(1) << (bit % MaxInlineBits));
+ const BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
+ return bits[offset] & bitFlagForBit(bit);
}
};
-bool QQmlData::wasDeleted(QObject *object)
+bool QQmlData::wasDeleted(const QObject *object)
{
if (!object)
return true;
- QObjectPrivate *priv = QObjectPrivate::get(object);
+ const QObjectPrivate *priv = QObjectPrivate::get(object);
if (!priv || priv->wasDeleted)
return true;
- QQmlData *ddata = QQmlData::get(object);
+ const QQmlData *ddata = QQmlData::get(object);
return ddata && ddata->isQueuedForDeletion;
}
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index a66bcaa9bd..4bc3c7d141 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -110,7 +110,10 @@ Q_DECLARE_METATYPE(QQmlProperty)
QT_BEGIN_NAMESPACE
typedef QQmlData::BindingBitsType BindingBitsType;
-enum { MaxInlineBits = QQmlData::MaxInlineBits };
+enum {
+ BitsPerType = QQmlData::BitsPerType,
+ InlineBindingArraySize = QQmlData::InlineBindingArraySize
+};
void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor)
{
@@ -747,11 +750,12 @@ QQmlData::QQmlData()
: ownedByQml1(false), ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
- bindingBitsSize(MaxInlineBits), bindingBitsValue(0), notifyList(0),
+ bindingBitsArraySize(InlineBindingArraySize), notifyList(0),
bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0),
lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0),
propertyCache(0), guards(0), extendedData(0)
{
+ memset(bindingBitsValue, 0, sizeof(bindingBitsValue));
init();
}
@@ -1825,7 +1829,7 @@ void QQmlData::destroyed(QObject *object)
signalHandler = next;
}
- if (bindingBitsSize > MaxInlineBits)
+ if (bindingBitsArraySize > InlineBindingArraySize)
free(bindingBits);
if (propertyCache)
@@ -1874,47 +1878,35 @@ void QQmlData::parentChanged(QObject *object, QObject *parent)
static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit)
{
- if (Q_UNLIKELY(data->bindingBitsSize <= bit)) {
+ uint offset = QQmlData::offsetForBit(bit);
+ BindingBitsType *bits = (data->bindingBitsArraySize == InlineBindingArraySize) ? data->bindingBitsValue : data->bindingBits;
+ if (Q_UNLIKELY(data->bindingBitsArraySize <= offset)) {
int props = QQmlMetaObject(obj).propertyCount();
Q_ASSERT(bit < 2 * props);
- int arraySize = (2 * props + MaxInlineBits - 1) / MaxInlineBits;
- Q_ASSERT(arraySize > 1);
-
- // special handling for 32 here is to make sure we wipe the first byte
- // when going from bindingBitsValue to bindingBits, and preserve the old
- // set bits so we can restore them after the allocation
- int oldArraySize = data->bindingBitsSize > MaxInlineBits ? data->bindingBitsSize / MaxInlineBits : 0;
- quintptr oldValue = data->bindingBitsSize == MaxInlineBits ? data->bindingBitsValue : 0;
-
- data->bindingBits = static_cast<BindingBitsType *>(realloc((data->bindingBitsSize == MaxInlineBits) ? 0 : data->bindingBits,
- arraySize * sizeof(BindingBitsType)));
-
- memset(data->bindingBits + oldArraySize,
- 0x00,
- sizeof(BindingBitsType) * (arraySize - oldArraySize));
+ uint arraySize = (2 * static_cast<uint>(props) + BitsPerType - 1) / BitsPerType;
+ Q_ASSERT(arraySize > InlineBindingArraySize && arraySize > data->bindingBitsArraySize);
- data->bindingBitsSize = arraySize * MaxInlineBits;
+ BindingBitsType *newBits = static_cast<BindingBitsType *>(malloc(arraySize*sizeof(BindingBitsType)));
+ memcpy(newBits, bits, data->bindingBitsArraySize * sizeof(BindingBitsType));
+ memset(newBits + data->bindingBitsArraySize, 0, sizeof(BindingBitsType) * (arraySize - data->bindingBitsArraySize));
- // reinstate bindingBitsValue after we dropped it
- if (oldValue) {
- memcpy(data->bindingBits, &oldValue, sizeof(oldValue));
- }
+ if (data->bindingBitsArraySize > InlineBindingArraySize)
+ free(bits);
+ data->bindingBits = newBits;
+ bits = newBits;
+ data->bindingBitsArraySize = arraySize;
}
-
- if (data->bindingBitsSize == MaxInlineBits)
- data->bindingBitsValue |= BindingBitsType(1) << bit;
- else
- data->bindingBits[bit / MaxInlineBits] |= (BindingBitsType(1) << (bit % MaxInlineBits));
+ Q_ASSERT(offset < data->bindingBitsArraySize);
+ bits[offset] |= QQmlData::bitFlagForBit(bit);
}
static void QQmlData_clearBit(QQmlData *data, int bit)
{
- if (data->bindingBitsSize > bit) {
- if (data->bindingBitsSize == MaxInlineBits)
- data->bindingBitsValue &= ~(BindingBitsType(1) << (bit % MaxInlineBits));
- else
- data->bindingBits[bit / MaxInlineBits] &= ~(BindingBitsType(1) << (bit % MaxInlineBits));
+ uint offset = QQmlData::offsetForBit(bit);
+ if (data->bindingBitsArraySize > offset) {
+ BindingBitsType *bits = (data->bindingBitsArraySize == InlineBindingArraySize) ? data->bindingBitsValue : data->bindingBits;
+ bits[offset] &= ~QQmlData::bitFlagForBit(bit);
}
}
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 6d0e4b915a..9855c27375 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -272,7 +272,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
if (!compilationUnit)
return;
- QML_MEMORY_SCOPE_URL(compilationUnit->url());
+ QML_MEMORY_SCOPE_URL(compilationUnit->finalUrl());
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this);
@@ -377,23 +377,6 @@ finishIncubate:
}
}
-void QQmlIncubatorPrivate::cancel(QObject *object, QQmlContext *context)
-{
- if (!context)
- context = qmlContext(object);
- if (!context)
- return;
-
- QQmlContextData *data = QQmlContextData::get(context);
- QQmlIncubatorPrivate *p = data->incubator;
- if (!p)
- return;
-
- p->vmeGuard.unguard(object);
- if (!p->creator.isNull())
- p->creator->cancel(object);
-}
-
/*!
Incubate objects for \a msecs, or until there are no more objects to incubate.
*/
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index 758e0a29f6..676ba1a29a 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -102,9 +102,6 @@ public:
void forceCompletion(QQmlInstantiationInterrupt &i);
void incubate(QQmlInstantiationInterrupt &i);
-
- // used by Qt Quick Controls 2
- Q_QML_PRIVATE_EXPORT static void cancel(QObject *object, QQmlContext *context = 0);
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 8d17ae3233..7616c5e38b 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -445,7 +445,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
QString string = binding->valueAsString(qmlUnit);
// Encoded dir-separators defeat QUrl processing - decode them first
string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- QUrl value = string.isEmpty() ? QUrl() : compilationUnit->url().resolved(QUrl(string));
+ QUrl value = string.isEmpty() ? QUrl() : compilationUnit->finalUrl().resolved(QUrl(string));
// Apply URL interceptor
if (engine->urlInterceptor())
value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
@@ -643,7 +643,8 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
} else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
QString urlString = binding->valueAsString(qmlUnit);
- QUrl u = urlString.isEmpty() ? QUrl() : compilationUnit->url().resolved(QUrl(urlString));
+ QUrl u = urlString.isEmpty() ? QUrl()
+ : compilationUnit->finalUrl().resolved(QUrl(urlString));
QList<QUrl> value;
value.append(u);
property->writeProperty(_qobject, &value, propertyWriteFlags);
@@ -1103,12 +1104,9 @@ void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::O
context->setIdProperty(object->id, instance);
}
-QV4::QmlContext *QQmlObjectCreator::currentQmlContext()
+void QQmlObjectCreator::createQmlContext()
{
- if (!_qmlContext->isManaged())
- _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject));
-
- return _qmlContext;
+ _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject));
}
QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
@@ -1357,21 +1355,6 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru
return sharedState->rootContext;
}
-void QQmlObjectCreator::cancel(QObject *object)
-{
- int last = sharedState->allCreatedObjects.count() - 1;
- int i = last;
- while (i >= 0) {
- if (sharedState->allCreatedObjects.at(i) == object) {
- if (i < last)
- qSwap(sharedState->allCreatedObjects[i], sharedState->allCreatedObjects[last]);
- sharedState->allCreatedObjects.pop();
- break;
- }
- --i;
- }
-}
-
void QQmlObjectCreator::clear()
{
if (phase == Done || phase == Finalizing || phase == Startup)
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 593d89e5d5..f4c03af5b7 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -92,7 +92,6 @@ public:
bool populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData);
bool populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding);
QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt);
- void cancel(QObject *object);
void clear();
QQmlComponentAttached **componentAttachment() const { return &sharedState->componentAttached; }
@@ -124,7 +123,8 @@ private:
void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const;
- QV4::QmlContext *currentQmlContext();
+ inline QV4::QmlContext *currentQmlContext();
+ Q_NEVER_INLINE void createQmlContext();
enum Phase {
Startup,
@@ -174,6 +174,14 @@ private:
QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher;
};
+QV4::QmlContext *QQmlObjectCreator::currentQmlContext()
+{
+ if (!_qmlContext->isManaged())
+ _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject));
+
+ return _qmlContext;
+}
+
QT_END_NAMESPACE
#endif // QQMLOBJECTCREATOR_P_H
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 9a138dcf80..50d9f13049 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -223,6 +223,22 @@ QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine
if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
}
+QQmlProperty QQmlPropertyPrivate::create(QObject *target, const QString &propertyName, QQmlContextData *context)
+{
+ QQmlProperty result;
+ auto d = new QQmlPropertyPrivate;
+ result.d = d;
+ d->context = context;
+ d->engine = context ? context->engine : nullptr;
+ d->initProperty(target, propertyName);
+ if (!result.isValid()) {
+ d->object = nullptr;
+ d->context = nullptr;
+ d->engine = nullptr;
+ }
+ return result;
+}
+
QQmlPropertyPrivate::QQmlPropertyPrivate()
: context(0), engine(0), object(0), isNameCached(false)
{
@@ -241,89 +257,93 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
QQmlTypeNameCache *typeNameCache = context?context->imports:0;
- const auto path = name.splitRef(QLatin1Char('.'));
- if (path.isEmpty()) return;
-
QObject *currentObject = obj;
-
- // Everything up to the last property must be an "object type" property
- for (int ii = 0; ii < path.count() - 1; ++ii) {
- const QStringRef &pathName = path.at(ii);
-
- if (typeNameCache) {
- QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
- if (r.isValid()) {
- if (r.type.isValid()) {
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
- QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
- if (!func) return; // Not an attachable type
-
- currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject);
- if (!currentObject) return; // Something is broken with the attachable type
- } else if (r.importNamespace) {
- if ((ii + 1) == path.count()) return; // No type following the namespace
-
- ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
- if (!r.type.isValid()) return; // Invalid type in namespace
-
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
- QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
- if (!func) return; // Not an attachable type
-
- currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject);
- if (!currentObject) return; // Something is broken with the attachable type
-
- } else if (r.scriptIndex != -1) {
- return; // Not a type
- } else {
- Q_ASSERT(!"Unreachable");
+ QVector<QStringRef> path;
+ QStringRef terminal(&name);
+
+ if (name.contains(QLatin1Char('.'))) {
+ path = name.splitRef(QLatin1Char('.'));
+ if (path.isEmpty()) return;
+
+ // Everything up to the last property must be an "object type" property
+ for (int ii = 0; ii < path.count() - 1; ++ii) {
+ const QStringRef &pathName = path.at(ii);
+
+ if (typeNameCache) {
+ QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
+ if (r.isValid()) {
+ if (r.type.isValid()) {
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
+ QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
+ if (!func) return; // Not an attachable type
+
+ currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject);
+ if (!currentObject) return; // Something is broken with the attachable type
+ } else if (r.importNamespace) {
+ if ((ii + 1) == path.count()) return; // No type following the namespace
+
+ ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
+ if (!r.type.isValid()) return; // Invalid type in namespace
+
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
+ QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
+ if (!func) return; // Not an attachable type
+
+ currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject);
+ if (!currentObject) return; // Something is broken with the attachable type
+
+ } else if (r.scriptIndex != -1) {
+ return; // Not a type
+ } else {
+ Q_ASSERT(!"Unreachable");
+ }
+ continue;
}
- continue;
+
}
- }
+ QQmlPropertyData local;
+ QQmlPropertyData *property =
+ QQmlPropertyCache::property(engine, currentObject, pathName, context, local);
- QQmlPropertyData local;
- QQmlPropertyData *property =
- QQmlPropertyCache::property(engine, currentObject, pathName, context, local);
+ if (!property) return; // Not a property
+ if (property->isFunction())
+ return; // Not an object property
- if (!property) return; // Not a property
- if (property->isFunction())
- return; // Not an object property
+ if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType())) {
+ // We're now at a value type property
+ const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType());
+ if (!valueTypeMetaObject) return; // Not a value type
- if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType())) {
- // We're now at a value type property
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType());
- if (!valueTypeMetaObject) return; // Not a value type
+ int idx = valueTypeMetaObject->indexOfProperty(path.last().toUtf8().constData());
+ if (idx == -1) return; // Value type property does not exist
- int idx = valueTypeMetaObject->indexOfProperty(path.last().toUtf8().constData());
- if (idx == -1) return; // Value type property does not exist
+ QMetaProperty vtProp = valueTypeMetaObject->property(idx);
- QMetaProperty vtProp = valueTypeMetaObject->property(idx);
+ Q_ASSERT(vtProp.userType() <= 0x0000FFFF);
+ Q_ASSERT(idx <= 0x0000FFFF);
- Q_ASSERT(vtProp.userType() <= 0x0000FFFF);
- Q_ASSERT(idx <= 0x0000FFFF);
+ object = currentObject;
+ core = *property;
+ valueTypeData.setFlags(QQmlPropertyData::flagsForProperty(vtProp));
+ valueTypeData.setPropType(vtProp.userType());
+ valueTypeData.setCoreIndex(idx);
- object = currentObject;
- core = *property;
- valueTypeData.setFlags(QQmlPropertyData::flagsForProperty(vtProp));
- valueTypeData.setPropType(vtProp.userType());
- valueTypeData.setCoreIndex(idx);
+ return;
+ } else {
+ if (!property->isQObject())
+ return; // Not an object property
- return;
- } else {
- if (!property->isQObject())
- return; // Not an object property
+ property->readProperty(currentObject, &currentObject);
+ if (!currentObject) return; // No value
- property->readProperty(currentObject, &currentObject);
- if (!currentObject) return; // No value
+ }
}
+ terminal = path.last();
}
- const QStringRef &terminal = path.last();
-
if (terminal.count() >= 3 &&
terminal.at(0) == QLatin1Char('o') &&
terminal.at(1) == QLatin1Char('n') &&
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index 53062a2f13..7a66d8113c 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -144,6 +144,8 @@ public:
static void flushSignal(const QObject *sender, int signal_index);
static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context);
+ static QQmlProperty create(QObject *target, const QString &propertyName, QQmlContextData *context);
+
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::BindingFlags)
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index fab5cf6c1f..c05126817e 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -357,8 +357,10 @@ qreal QQmlDataBlob::progress() const
}
/*!
-Returns the blob url passed to the constructor. If a network redirect
-happens while fetching the data, this url remains the same.
+Returns the physical url of the data. Initially this is the same as
+finalUrl(), but if a network redirect happens while fetching the data, this url
+is updated to reflect the new location. Also, if a URL interceptor is set, it
+will work on this URL and leave finalUrl() alone.
\sa finalUrl()
*/
@@ -367,16 +369,25 @@ QUrl QQmlDataBlob::url() const
return m_url;
}
+QString QQmlDataBlob::urlString() const
+{
+ if (m_urlString.isEmpty())
+ m_urlString = m_url.toString();
+
+ return m_urlString;
+}
+
/*!
-Returns the final url of the data. Initially this is the same as
-url(), but if a network redirect happens while fetching the data, this url
-is updated to reflect the new location.
+Returns the logical URL to be used for resolving further URLs referred to in
+the code.
-May only be called from the load thread, or after the blob isCompleteOrError().
+This is the blob url passed to the constructor. If a network redirect
+happens while fetching the data, this url remains the same.
+
+\sa url()
*/
QUrl QQmlDataBlob::finalUrl() const
{
- Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread()));
return m_finalUrl;
}
@@ -385,7 +396,6 @@ Returns the finalUrl() as a string.
*/
QString QQmlDataBlob::finalUrlString() const
{
- Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread()));
if (m_finalUrlString.isEmpty())
m_finalUrlString = m_finalUrl.toString();
@@ -434,7 +444,7 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors)
m_data.setStatus(Error);
if (dumpErrors()) {
- qWarning().nospace() << "Errors for " << m_finalUrl.toString();
+ qWarning().nospace() << "Errors for " << urlString();
for (int ii = 0; ii < errors.count(); ++ii)
qWarning().nospace() << " " << qPrintable(errors.at(ii).toString());
}
@@ -473,7 +483,7 @@ void QQmlDataBlob::setError(const QString &description)
{
QQmlError e;
e.setDescription(description);
- e.setUrl(finalUrl());
+ e.setUrl(url());
setError(e);
}
@@ -538,7 +548,7 @@ void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError)
Q_UNUSED(networkError);
QQmlError error;
- error.setUrl(m_finalUrl);
+ error.setUrl(m_url);
const char *errorString = 0;
switch (networkError) {
@@ -655,7 +665,7 @@ void QQmlDataBlob::tryDone()
addref();
#ifdef DATABLOB_DEBUG
- qWarning("QQmlDataBlob::done() %s", qPrintable(url().toString()));
+ qWarning("QQmlDataBlob::done() %s", qPrintable(urlString()));
#endif
done();
@@ -894,7 +904,7 @@ void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b)
{
QML_MEMORY_SCOPE_URL(b->url());
#ifdef DATABLOB_DEBUG
- qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->url().toString()));
+ qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString()));
#endif
b->completed();
b->release();
@@ -904,7 +914,7 @@ void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qrea
{
#ifdef DATABLOB_DEBUG
qWarning("QQmlTypeLoaderThread: %s downloadProgressChanged(%f) callback",
- qPrintable(b->url().toString()), p);
+ qPrintable(b->urlString()), p);
#endif
b->downloadProgressChanged(p);
b->release();
@@ -1038,7 +1048,7 @@ template<typename Loader>
void QQmlTypeLoader::doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode)
{
#ifdef DATABLOB_DEBUG
- qWarning("QQmlTypeLoader::doLoad(%s): %s thread", qPrintable(blob->m_url.toString()),
+ qWarning("QQmlTypeLoader::doLoad(%s): %s thread", qPrintable(blob->urlString()),
m_thread->isThisThread()?"Compile":"Engine");
#endif
blob->startLoading();
@@ -1160,7 +1170,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
}
#ifdef DATABLOB_DEBUG
- qWarning("QQmlDataBlob: requested %s", qPrintable(blob->url().toString()));
+ qWarning("QQmlDataBlob: requested %s", qPrintable(blob->urlString()));
#endif // DATABLOB_DEBUG
#endif // qml_network
}
@@ -1186,14 +1196,15 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (redirect.isValid()) {
QUrl url = reply->url().resolved(redirect.toUrl());
- blob->m_finalUrl = url;
+ blob->m_url = url;
+ blob->m_urlString.clear();
QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(url));
QObject *nrp = m_thread->networkReplyProxy();
QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished()));
m_networkReplies.insert(reply, blob);
#ifdef DATABLOB_DEBUG
- qWarning("QQmlDataBlob: redirected to %s", qPrintable(blob->m_finalUrl.toString()));
+ qWarning("QQmlDataBlob: redirected to %s", qPrintable(blob->urlString()));
#endif
return;
}
@@ -1349,7 +1360,7 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData:
bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
{
- QString qmldirIdentifier = data->url().toString();
+ QString qmldirIdentifier = data->urlString();
QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char('/')) + 1);
typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
@@ -2105,7 +2116,7 @@ bool QQmlTypeData::tryLoadFromDiskCache()
{
QString error;
if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
- qCDebug(DBG_DISK_CACHE) << "Error loading" << url().toString() << "from disk cache:" << error;
+ qCDebug(DBG_DISK_CACHE) << "Error loading" << urlString() << "from disk cache:" << error;
return false;
}
}
@@ -2225,10 +2236,10 @@ void QQmlTypeData::done()
if (script.script->isError()) {
QList<QQmlError> errors = script.script->errors();
QQmlError error;
- error.setUrl(finalUrl());
+ error.setUrl(url());
error.setLine(script.location.line);
error.setColumn(script.location.column);
- error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString()));
+ error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
errors.prepend(error);
setError(errors);
return;
@@ -2245,7 +2256,7 @@ void QQmlTypeData::done()
QList<QQmlError> errors = type.typeData->errors();
QQmlError error;
- error.setUrl(finalUrl());
+ error.setUrl(url());
error.setLine(type.location.line);
error.setColumn(type.location.column);
error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
@@ -2264,7 +2275,7 @@ void QQmlTypeData::done()
QList<QQmlError> errors = type.typeData->errors();
QQmlError error;
- error.setUrl(finalUrl());
+ error.setUrl(url());
error.setLine(type.location.line);
error.setColumn(type.location.column);
error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
@@ -2294,7 +2305,7 @@ void QQmlTypeData::done()
// verify if any dependencies changed if we're using a cache
if (m_document.isNull() && !m_compiledData->verifyChecksum(dependencyHasher)) {
- qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->url().toString();
+ qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->fileName();
if (!loadFromSource())
return;
m_backupSourceCode = SourceCodeData();
@@ -2430,7 +2441,8 @@ void QQmlTypeData::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
m_document.reset(new QmlIR::Document(isDebugging()));
QmlIR::IRLoader loader(unit, m_document.data());
loader.load();
- m_document->jsModule.fileName = finalUrlString();
+ m_document->jsModule.fileName = urlString();
+ m_document->jsModule.finalUrl = finalUrlString();
m_document->javaScriptCompilationUnit.adopt(new QV4::CompiledData::CompilationUnit(unit));
continueLoadFromIR();
}
@@ -2454,7 +2466,7 @@ bool QQmlTypeData::loadFromSource()
errors.reserve(compiler.errors.count());
for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
QQmlError e;
- e.setUrl(finalUrl());
+ e.setUrl(url());
e.setLine(msg.loc.startLine);
e.setColumn(msg.loc.startColumn);
e.setDescription(msg.message);
@@ -2471,7 +2483,8 @@ void QQmlTypeData::restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit>
m_document.reset(new QmlIR::Document(isDebugging()));
QmlIR::IRLoader loader(unit->data, m_document.data());
loader.load();
- m_document->jsModule.fileName = finalUrlString();
+ m_document->jsModule.fileName = urlString();
+ m_document->jsModule.finalUrl = finalUrlString();
m_document->javaScriptCompilationUnit = unit;
continueLoadFromIR();
}
@@ -2594,7 +2607,7 @@ void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCach
// ignore error, keep using the in-memory compilation unit.
}
} else {
- qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->url().toString() << "to disk:" << errorString;
+ qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->fileName() << "to disk:" << errorString;
}
}
}
@@ -2962,7 +2975,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
initializeFromCompilationUnit(unit);
return;
} else {
- qCDebug(DBG_DISK_CACHE()) << "Error loading" << url().toString() << "from disk cache:" << error;
+ qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error;
}
}
@@ -2980,7 +2993,9 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
QmlIR::ScriptDirectivesCollector collector(&irUnit.jsParserEngine, &irUnit.jsGenerator);
QList<QQmlError> errors;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Script::precompile(&irUnit.jsModule, &irUnit.jsGenerator, finalUrl(), source, &errors, &collector);
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Script::precompile(
+ &irUnit.jsModule, &irUnit.jsGenerator, urlString(), finalUrlString(),
+ source, &errors, &collector);
// No need to addref on unit, it's initial refcount is 1
source.clear();
if (!errors.isEmpty()) {
@@ -3004,7 +3019,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
if (!disableDiskCache() || forceDiskCache()) {
QString errorString;
if (!unit->saveToDisk(url(), &errorString)) {
- qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->url().toString() << "to disk:" << errorString;
+ qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->fileName() << "to disk:" << errorString;
}
}
@@ -3030,10 +3045,10 @@ void QQmlScriptBlob::done()
if (script.script->isError()) {
QList<QQmlError> errors = script.script->errors();
QQmlError error;
- error.setUrl(finalUrl());
+ error.setUrl(url());
error.setLine(script.location.line);
error.setColumn(script.location.column);
- error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString()));
+ error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
errors.prepend(error);
setError(errors);
return;
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index d5386e48ed..875c335c9a 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -129,6 +129,7 @@ public:
qreal progress() const;
QUrl url() const;
+ QString urlString() const;
QUrl finalUrl() const;
QString finalUrlString() const;
@@ -207,6 +208,7 @@ private:
QUrl m_url;
QUrl m_finalUrl;
+ mutable QString m_urlString;
mutable QString m_finalUrlString;
// List of QQmlDataBlob's that are waiting for me to complete.
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index c60f4edc80..72d4ab7e8f 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -120,18 +120,6 @@ void QQmlVMEGuard::guard(QQmlObjectCreator *creator)
m_contexts[0] = creator->parentContextData();
}
-void QQmlVMEGuard::unguard(QObject *object)
-{
- for (int ii = 0; ii < m_objectCount; ++ii) {
- if (m_objects[ii] == object) {
- if (ii < m_objectCount - 1)
- ::memmove((void *) m_objects[ii], (void *) m_objects[ii + 1], sizeof(QPointer<QObject> *));
- delete m_objects[--m_objectCount];
- break;
- }
- }
-}
-
void QQmlVMEGuard::clear()
{
delete [] m_objects;
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index 9585b5b6df..99d63380ad 100644
--- a/src/qml/qml/qqmlvme_p.h
+++ b/src/qml/qml/qqmlvme_p.h
@@ -131,7 +131,6 @@ public:
~QQmlVMEGuard();
void guard(QQmlObjectCreator *);
- void unguard(QObject *);
void clear();
bool isOK() const;
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index fa1be563b5..4e4a9353cb 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -863,7 +863,7 @@ void QQmlDelegateModelPrivate::releaseIncubator(QQDMIncubationTask *incubationTa
void QQmlDelegateModelPrivate::removeCacheItem(QQmlDelegateModelItem *cacheItem)
{
- int cidx = m_cache.indexOf(cacheItem);
+ int cidx = m_cache.lastIndexOf(cacheItem);
if (cidx >= 0) {
m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
m_cache.removeAt(cidx);
@@ -1020,11 +1020,11 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
/*
If asynchronous is true or the component is being loaded asynchronously due
- to an ancestor being loaded asynchronously, item() may return 0. In this
- case createdItem() will be emitted when the item is available. The item
- at this stage does not have any references, so item() must be called again
- to ensure a reference is held. Any call to item() which returns a valid item
- must be matched by a call to release() in order to destroy the item.
+ to an ancestor being loaded asynchronously, object() may return 0. In this
+ case createdItem() will be emitted when the object is available. The object
+ at this stage does not have any references, so object() must be called again
+ to ensure a reference is held. Any call to object() which returns a valid object
+ must be matched by a call to release() in order to destroy the object.
*/
QObject *QQmlDelegateModel::object(int index, QQmlIncubator::IncubationMode incubationMode)
{
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index 27576d488c..99175ab94e 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -176,8 +176,8 @@ attach application code. This can be used to add custom scene graph
content or render raw OpenGL content. The integration points are
defined by the render loop.
-For detailed description of how the scene graph renderer works, see
-\l {Qt Quick Scene Graph Renderer}.
+For detailed description of how the scene graph renderer for OpenGL
+works, see \l {Qt Quick Scene Graph OpenGL Renderer}.
There are three render loop variants available: \c basic, \c windows,
and \c threaded. Out of these, \c basic and \c windows are
@@ -413,10 +413,11 @@ with multiple windows.
*/
/*!
- \title Qt Quick Scene Graph Renderer
+ \title Qt Quick Scene Graph OpenGL Renderer
\page qtquick-visualcanvas-scenegraph-renderer.html
- This document explains how the scene graph renderer works internally
+ This document explains how the scene graph renderer for OpenGL
+ works internally
so that one can write code that uses it in an optimal fashion, both
performance-wise and feature-wise.
@@ -428,7 +429,7 @@ with multiple windows.
\note Even in the case where every frame is unique and everything is
uploaded from scratch, the default renderer will perform well.
- The Qt Quick items in a QML scene populates a tree of QSGNode
+ The Qt Quick items in a QML scene populate a tree of QSGNode
instances. Once created, this tree is a complete description of how
a certain frame should be rendered. It does not contain any
references back to the Qt Quick items at all and will on most
@@ -441,11 +442,11 @@ with multiple windows.
If needed, the renderer can be completely replaced using the
internal scene graph back-end API. This is mostly interesting for
platform vendors who wish to take advantage of non-standard hardware
- features. For majority of use cases, the default renderer will be
+ features. For the majority of use cases, the default renderer will be
sufficient.
The default renderer focuses on two primary strategies to optimize
- the rendering. Batching of draw calls and retention of geometry on
+ the rendering: Batching of draw calls, and retention of geometry on
the GPU.
\section1 Batching
@@ -458,7 +459,7 @@ with multiple windows.
\image visualcanvas_list.png
- The simplest way of drawing this list is on a cell-by-cell basis. First
+ The simplest way of drawing this list is on a cell-by-cell basis. First,
the background is drawn. This is a rectangle of a specific color. In
OpenGL terms this means selecting a shader program to do solid color
fills, setting up the fill color, setting the transformation matrix
@@ -495,8 +496,8 @@ with multiple windows.
batches. From Qt Quick core item set, this includes Rectangle items
with opaque colors and fully opaque images, such as JPEGs or BMPs.
- Another benefit of using opaque primitives, is that opaque
- primitives does not require \c GL_BLEND to be enabled which can be
+ Another benefit of using opaque primitives is that opaque
+ primitives do not require \c GL_BLEND to be enabled, which can be
quite costly, especially on mobile and embedded GPUs.
Opaque primitives are rendered in a front-to-back manner with
@@ -533,7 +534,7 @@ with multiple windows.
and the two text elements in another call, as the texts only overlap
a background which they are stacked in front of. In the right-most
case, the background of "Item 4" overlaps the text of "Item 3" so in
- this case, each of backgrounds and texts need to be drawn using
+ this case, each of backgrounds and texts needs to be drawn using
separate calls.
Z-wise, the alpha primitives are interleaved with the opaque nodes
@@ -550,7 +551,7 @@ with multiple windows.
The renderer modifies the vertex shader returned from
QSGMaterialShader::vertexShader() and compresses the z values of the
- vertex after the model-view and projection matrices has been applied
+ vertex after the model-view and projection matrices have been applied
and then adds a small translation on the z to position it the
correct z position.
@@ -561,7 +562,7 @@ with multiple windows.
The active texture is a unique OpenGL state, which means that
multiple primitives using different OpenGL textures cannot be
- batched. The Qt Quick scene graph for this reason allows multiple
+ batched. The Qt Quick scene graph, for this reason, allows multiple
QSGTexture instances to be allocated as smaller sub-regions of a
larger texture; a texture atlas.
@@ -603,10 +604,10 @@ with multiple windows.
Each Qt Quick Item inserts a QSGTransformNode into the scene graph
tree to manage its x, y, scale or rotation. Child items will be
populated under this transform node. The default renderer tracks
- the state of transform nodes between frames, and will look at
+ the state of transform nodes between frames and will look at
subtrees to decide if a transform node is a good candidate to become
a root for a set of batches. A transform node which changes between
- frames and which has a fairly complex subtree, can become a batch
+ frames and which has a fairly complex subtree can become a batch
root.
QSGGeometryNodes in the subtree of a batch root are pre-transformed
@@ -621,7 +622,7 @@ with multiple windows.
removed nodes when panning through a grid or list.
Another benefit of identifying transform nodes as batch roots is
- that it allows the renderer to retain the parts of the tree that has
+ that it allows the renderer to retain the parts of the tree that have
not changed. For instance, say a UI consists of a list and a button
row. When the list is being scrolled and delegates are being added
and removed, the rest of the UI, the button row, is unchanged and
@@ -684,7 +685,7 @@ with multiple windows.
to either \c vertex or \c {msaa}.
Vertex antialiasing can produce seams between edges of adjacent
- primitives, even when the two edges are mathmatically the same.
+ primitives, even when the two edges are mathematically the same.
Multisample antialiasing does not.
@@ -722,7 +723,7 @@ with multiple windows.
job when creating batches and can rely on early-z to avoid overdraw.
When multisample antialiasing is used, content rendered into
- framebuffer objects, need additional extensions to support multisampling
+ framebuffer objects need additional extensions to support multisampling
of framebuffers. Typically \c GL_EXT_framebuffer_multisample and
\c GL_EXT_framebuffer_blit. Most desktop chips have these extensions
present, but they are less common in embedded chips. When framebuffer
@@ -736,7 +737,7 @@ with multiple windows.
As stated in the beginning, understanding the finer details of the
renderer is not required to get good performance. It is written to
optimize for common use cases and will perform quite well under
- almost any circumstance.
+ almost any circumstances.
\list
@@ -744,7 +745,7 @@ with multiple windows.
as possible of the geometry being uploaded again and again. By
setting the environment variable \c {QSG_RENDERER_DEBUG=render}, the
renderer will output statistics on how well the batching goes, how
- many batches, which batches are retained and which are opaque and
+ many batches are used, which batches are retained and which are opaque and
not. When striving for optimal performance, uploads should happen
only when really needed, batches should be fewer than 10 and at
least 3-4 of them should be opaque.
@@ -772,16 +773,16 @@ with multiple windows.
QQuickWindow::createTextureFromImage(), let the image have
QImage::Format_RGB32, when possible.
- \li Be aware of that overlapping compond items, like in the
- illustration above, can not be batched.
+ \li Be aware of that overlapping compound items, like in the
+ illustration above, cannot be batched.
\li Clipping breaks batching. Never use on a per-item basis, inside
- tables cells, item delegates or similar. Instead of clipping text,
+ table cells, item delegates or similar. Instead of clipping text,
use eliding. Instead of clipping an image, create a
QQuickImageProvider that returns a cropped image.
\li Batching only works for 16-bit indices. All built-in items use
- 16-bit indices, but custom geometry is free to also use 32-bit
+ 16-bit indices, but a custom geometry is free to also use 32-bit
indices.
\li Some material flags prevent batching, the most limiting one
@@ -792,7 +793,7 @@ with multiple windows.
QQuickWindow::setColor() will be used in a call to \c glClear(),
which is potentially faster.
- \li Mipmapped Image items are not placed in global atlas and will
+ \li Mipmapped Image items are not placed in the global atlas and will
not be batched.
\endlist
diff --git a/src/quick/doc/src/qtquick.qdoc b/src/quick/doc/src/qtquick.qdoc
index e2d4f16dae..ece66cb589 100644
--- a/src/quick/doc/src/qtquick.qdoc
+++ b/src/quick/doc/src/qtquick.qdoc
@@ -89,7 +89,8 @@ To find out more about using the QML language, see the \l{Qt QML} module documen
\section1 Licenses and Attributions
Qt Quick is available under commercial licenses from \l{The Qt Company}.
-In addition, it is available under the
+In addition, it is available under free software licenses. Since Qt 5.4,
+these free software licenses are
\l{GNU Lesser General Public License, version 3}, or
the \l{GNU General Public License, version 2}.
See \l{Qt Licensing} for further details.
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp
index 4180714f86..5c9f893b63 100644
--- a/src/quick/items/qquickanimatedimage.cpp
+++ b/src/quick/items/qquickanimatedimage.cpp
@@ -54,26 +54,26 @@ QT_BEGIN_NAMESPACE
QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine)
{
- if (!_movie)
+ if (!movie)
return 0;
- int current = _movie->currentFrameNumber();
+ int current = movie->currentFrameNumber();
if (!frameMap.contains(current)) {
QUrl requestedUrl;
QQuickPixmap *pixmap = 0;
- if (engine && !_movie->fileName().isEmpty()) {
+ if (engine && !movie->fileName().isEmpty()) {
requestedUrl.setUrl(QString::fromUtf8("quickanimatedimage://%1#%2")
- .arg(_movie->fileName())
+ .arg(movie->fileName())
.arg(current));
}
if (!requestedUrl.isEmpty()) {
if (QQuickPixmap::isCached(requestedUrl, QSize(), QQuickImageProviderOptions()))
pixmap = new QQuickPixmap(engine, requestedUrl);
else
- pixmap = new QQuickPixmap(requestedUrl, _movie->currentImage());
+ pixmap = new QQuickPixmap(requestedUrl, movie->currentImage());
} else {
pixmap = new QQuickPixmap;
- pixmap->setImage(_movie->currentImage());
+ pixmap->setImage(movie->currentImage());
}
frameMap.insert(current, pixmap);
}
@@ -138,7 +138,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine
QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
: QQuickImage(*(new QQuickAnimatedImagePrivate), parent)
{
- QObject::connect(this, &QQuickImageBase::cacheChanged, this, &QQuickAnimatedImage::onCacheChanged);
+ connect(this, &QQuickImageBase::cacheChanged, this, &QQuickAnimatedImage::onCacheChanged);
}
QQuickAnimatedImage::~QQuickAnimatedImage()
@@ -148,7 +148,7 @@ QQuickAnimatedImage::~QQuickAnimatedImage()
if (d->reply)
d->reply->deleteLater();
#endif
- delete d->_movie;
+ delete d->movie;
qDeleteAll(d->frameMap);
d->frameMap.clear();
}
@@ -164,9 +164,9 @@ QQuickAnimatedImage::~QQuickAnimatedImage()
bool QQuickAnimatedImage::isPaused() const
{
Q_D(const QQuickAnimatedImage);
- if (!d->_movie)
+ if (!d->movie)
return d->paused;
- return d->_movie->state()==QMovie::Paused;
+ return d->movie->state()==QMovie::Paused;
}
void QQuickAnimatedImage::setPaused(bool pause)
@@ -174,11 +174,11 @@ void QQuickAnimatedImage::setPaused(bool pause)
Q_D(QQuickAnimatedImage);
if (pause == d->paused)
return;
- if (!d->_movie) {
+ if (!d->movie) {
d->paused = pause;
emit pausedChanged();
} else {
- d->_movie->setPaused(pause);
+ d->movie->setPaused(pause);
}
}
@@ -203,9 +203,9 @@ void QQuickAnimatedImage::setPaused(bool pause)
bool QQuickAnimatedImage::isPlaying() const
{
Q_D(const QQuickAnimatedImage);
- if (!d->_movie)
+ if (!d->movie)
return d->playing;
- return d->_movie->state()!=QMovie::NotRunning;
+ return d->movie->state()!=QMovie::NotRunning;
}
void QQuickAnimatedImage::setPlaying(bool play)
@@ -213,15 +213,15 @@ void QQuickAnimatedImage::setPlaying(bool play)
Q_D(QQuickAnimatedImage);
if (play == d->playing)
return;
- if (!d->_movie) {
+ if (!d->movie) {
d->playing = play;
emit playingChanged();
return;
}
if (play)
- d->_movie->start();
+ d->movie->start();
else
- d->_movie->stop();
+ d->movie->stop();
}
/*!
@@ -237,27 +237,27 @@ void QQuickAnimatedImage::setPlaying(bool play)
int QQuickAnimatedImage::currentFrame() const
{
Q_D(const QQuickAnimatedImage);
- if (!d->_movie)
- return d->preset_currentframe;
- return d->_movie->currentFrameNumber();
+ if (!d->movie)
+ return d->presetCurrentFrame;
+ return d->movie->currentFrameNumber();
}
void QQuickAnimatedImage::setCurrentFrame(int frame)
{
Q_D(QQuickAnimatedImage);
- if (!d->_movie) {
- d->preset_currentframe = frame;
+ if (!d->movie) {
+ d->presetCurrentFrame = frame;
return;
}
- d->_movie->jumpToFrame(frame);
+ d->movie->jumpToFrame(frame);
}
int QQuickAnimatedImage::frameCount() const
{
Q_D(const QQuickAnimatedImage);
- if (!d->_movie)
+ if (!d->movie)
return 0;
- return d->_movie->frameCount();
+ return d->movie->frameCount();
}
/*!
@@ -280,8 +280,8 @@ void QQuickAnimatedImage::setSpeed(qreal speed)
Q_D(QQuickAnimatedImage);
if (d->speed != speed) {
d->speed = speed;
- if (d->_movie)
- d->_movie->setSpeed(qRound(speed * 100.0));
+ if (d->movie)
+ d->movie->setSpeed(qRound(speed * 100.0));
emit speedChanged();
}
}
@@ -304,10 +304,7 @@ void QQuickAnimatedImage::setSource(const QUrl &url)
d->frameMap.clear();
d->oldPlaying = isPlaying();
- if (d->_movie) {
- d->setMovie(nullptr);
- }
-
+ d->setMovie(nullptr);
d->url = url;
emit sourceChanged(d->url);
@@ -361,10 +358,8 @@ void QQuickAnimatedImage::load()
req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
d->reply = qmlEngine(this)->networkAccessManager()->get(req);
- QObject::connect(d->reply, SIGNAL(finished()),
- this, SLOT(movieRequestFinished()));
- QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
- this, SLOT(requestProgress(qint64,qint64)));
+ connect(d->reply, &QNetworkReply::finished, this, &QQuickAnimatedImage::movieRequestFinished);
+ connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(requestProgress(qint64,qint64)));
#endif
}
}
@@ -395,7 +390,7 @@ void QQuickAnimatedImage::movieRequestFinished()
}
#endif
- if (!d->_movie || !d->_movie->isValid()) {
+ if (!d->movie || !d->movie->isValid()) {
qmlWarning(this) << "Error Reading Animated Image File " << d->url.toString();
d->setMovie(nullptr);
d->setImage(QImage());
@@ -416,13 +411,11 @@ void QQuickAnimatedImage::movieRequestFinished()
return;
}
- connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
- this, SLOT(playingStatusChanged()));
- connect(d->_movie, SIGNAL(frameChanged(int)),
- this, SLOT(movieUpdate()));
+ connect(d->movie, &QMovie::stateChanged, this, &QQuickAnimatedImage::playingStatusChanged);
+ connect(d->movie, &QMovie::frameChanged, this, &QQuickAnimatedImage::movieUpdate);
if (d->cache)
- d->_movie->setCacheMode(QMovie::CacheAll);
- d->_movie->setSpeed(qRound(d->speed * 100.0));
+ d->movie->setCacheMode(QMovie::CacheAll);
+ d->movie->setSpeed(qRound(d->speed * 100.0));
d->status = Ready;
emit statusChanged(d->status);
@@ -433,22 +426,21 @@ void QQuickAnimatedImage::movieRequestFinished()
}
bool pausedAtStart = d->paused;
- if (d->playing) {
- d->_movie->start();
- }
+ if (d->playing)
+ d->movie->start();
if (pausedAtStart)
- d->_movie->setPaused(true);
+ d->movie->setPaused(true);
if (d->paused || !d->playing) {
- d->_movie->jumpToFrame(d->preset_currentframe);
- d->preset_currentframe = 0;
+ d->movie->jumpToFrame(d->presetCurrentFrame);
+ d->presetCurrentFrame = 0;
}
d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this)));
if (isPlaying() != d->oldPlaying)
emit playingChanged();
- if (d->_movie)
- d->currentSourceSize = d->_movie->currentPixmap().size();
+ if (d->movie)
+ d->currentSourceSize = d->movie->currentPixmap().size();
else
d->currentSourceSize = QSize(0, 0);
@@ -467,7 +459,7 @@ void QQuickAnimatedImage::movieUpdate()
d->frameMap.clear();
}
- if (d->_movie) {
+ if (d->movie) {
d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this)));
emit frameChanged();
}
@@ -477,12 +469,12 @@ void QQuickAnimatedImage::playingStatusChanged()
{
Q_D(QQuickAnimatedImage);
- if ((d->_movie->state() != QMovie::NotRunning) != d->playing) {
- d->playing = (d->_movie->state() != QMovie::NotRunning);
+ if ((d->movie->state() != QMovie::NotRunning) != d->playing) {
+ d->playing = (d->movie->state() != QMovie::NotRunning);
emit playingChanged();
}
- if ((d->_movie->state() == QMovie::Paused) != d->paused) {
- d->paused = (d->_movie->state() == QMovie::Paused);
+ if ((d->movie->state() == QMovie::Paused) != d->paused) {
+ d->paused = (d->movie->state() == QMovie::Paused);
emit pausedChanged();
}
}
@@ -493,13 +485,11 @@ void QQuickAnimatedImage::onCacheChanged()
if (!cache()) {
qDeleteAll(d->frameMap);
d->frameMap.clear();
- if (d->_movie) {
- d->_movie->setCacheMode(QMovie::CacheNone);
- }
+ if (d->movie)
+ d->movie->setCacheMode(QMovie::CacheNone);
} else {
- if (d->_movie) {
- d->_movie->setCacheMode(QMovie::CacheAll);
- }
+ if (d->movie)
+ d->movie->setCacheMode(QMovie::CacheAll);
}
}
@@ -515,13 +505,15 @@ void QQuickAnimatedImage::componentComplete()
load();
}
-void QQuickAnimatedImagePrivate::setMovie(QMovie *movie)
+void QQuickAnimatedImagePrivate::setMovie(QMovie *m)
{
+ if (movie == m)
+ return;
Q_Q(QQuickAnimatedImage);
const int oldFrameCount = q->frameCount();
- delete _movie;
- _movie = movie;
+ delete movie;
+ movie = m;
if (oldFrameCount != q->frameCount())
emit q->frameCountChanged();
diff --git a/src/quick/items/qquickanimatedimage_p_p.h b/src/quick/items/qquickanimatedimage_p_p.h
index ef30c39fed..1a74f67424 100644
--- a/src/quick/items/qquickanimatedimage_p_p.h
+++ b/src/quick/items/qquickanimatedimage_p_p.h
@@ -70,29 +70,30 @@ class QQuickAnimatedImagePrivate : public QQuickImagePrivate
public:
QQuickAnimatedImagePrivate()
- : playing(true), paused(false), speed(1.0), preset_currentframe(0), _movie(0), oldPlaying(false)
+ : playing(true), paused(false), oldPlaying(false), padding(0)
+ , presetCurrentFrame(0), speed(1.0), currentSourceSize(0, 0), movie(nullptr)
#if QT_CONFIG(qml_network)
- , reply(0), redirectCount(0)
+ , reply(nullptr), redirectCount(0)
#endif
- , currentSourceSize(0, 0)
{
}
QQuickPixmap *infoForCurrentFrame(QQmlEngine *engine);
+ void setMovie(QMovie *movie);
- bool playing;
- bool paused;
+ bool playing : 1;
+ bool paused : 1;
+ bool oldPlaying : 1;
+ unsigned padding: 29;
+ int presetCurrentFrame;
qreal speed;
- int preset_currentframe;
- QMovie *_movie;
- bool oldPlaying;
+ QSize currentSourceSize;
+ QMovie *movie;
#if QT_CONFIG(qml_network)
QNetworkReply *reply;
int redirectCount;
#endif
QMap<int, QQuickPixmap *> frameMap;
- QSize currentSourceSize;
- void setMovie(QMovie *movie);
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index bec5f06d72..95d1229c8d 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -1435,17 +1435,23 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
case Qt::ScrollUpdate:
if (d->scrollingPhase)
d->pressed = true;
-#ifdef Q_OS_OSX
+#ifdef Q_OS_MACOS
+ // TODO eliminate this timer when ScrollMomentum has been added
d->movementEndingTimer.start(MovementEndingTimerInterval, this);
#endif
break;
case Qt::ScrollEnd:
+ // TODO most of this should be done at transition to ScrollMomentum phase,
+ // then do what the movementEndingTimer triggers at transition to ScrollEnd phase
d->pressed = false;
d->scrollingPhase = false;
d->draggingEnding();
event->accept();
returnToBounds();
d->lastPosTime = -1;
+#ifdef Q_OS_MACOS
+ d->movementEndingTimer.start(MovementEndingTimerInterval, this);
+#endif
return;
}
@@ -2670,13 +2676,15 @@ void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding)
if (hMovementEnding && d->hData.moving
&& (!d->pressed && !d->stealMouse)) {
d->hData.moving = false;
- d->hMoved = false;
+ if (!d->scrollingPhase)
+ d->hMoved = false;
emit movingHorizontallyChanged();
}
if (vMovementEnding && d->vData.moving
&& (!d->pressed && !d->stealMouse)) {
d->vData.moving = false;
- d->vMoved = false;
+ if (!d->scrollingPhase)
+ d->vMoved = false;
emit movingVerticallyChanged();
}
if (wasMoving && !isMoving()) {
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 54cc67875a..c2531e6012 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -106,9 +106,10 @@ public:
, continuousFlickVelocity(0), velocityTime(), vTime(0)
, smoothVelocity(fp), atEnd(false), atBeginning(true)
, transitionToSet(false)
- , fixingUp(false), inOvershoot(false), moving(false), flicking(false)
+ , fixingUp(false), inOvershoot(false), inRebound(false), moving(false), flicking(false)
, dragging(false), extentsChanged(false)
, explicitValue(false), minExtentDirty(true), maxExtentDirty(true)
+ , unused(0)
{}
~AxisData();
@@ -168,6 +169,7 @@ public:
bool explicitValue : 1;
mutable bool minExtentDirty : 1;
mutable bool maxExtentDirty : 1;
+ uint unused : 19;
};
bool flickX(qreal velocity);
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index 5a40d6b705..9b133a823e 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -313,6 +313,7 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode
desiredFboSize *= n->devicePixelRatio;
if (n->fbo && ((d->followsItemSize && n->fbo->size() != desiredFboSize) || n->invalidatePending)) {
+ delete n->texture();
delete n->fbo;
n->fbo = 0;
delete n->msDisplayFbo;
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index f68dfbf581..b2adf96f0e 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -537,13 +537,12 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
if (visibleItems.count()) {
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.constFirst());
rowPos = firstItem->rowPos();
- colNum = qFloor((firstItem->colPos()+colSize()/2) / colSize());
- if (--colNum < 0) {
- colNum = columns - 1;
- rowPos -= rowSize();
- }
- } else {
- colNum = qFloor((colPos+colSize()/2) / colSize());
+ colPos = firstItem->colPos();
+ }
+ colNum = qFloor((colPos+colSize()/2) / colSize());
+ if (--colNum < 0) {
+ colNum = columns - 1;
+ rowPos -= rowSize();
}
// Prepend
@@ -894,7 +893,6 @@ void QQuickGridViewPrivate::initializeCurrentItem()
void QQuickGridViewPrivate::fixupPosition()
{
- moveReason = Other;
if (flow == QQuickGridView::FlowLeftToRight)
fixupY();
else
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index f4d11e32bd..f615e85e1b 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -87,6 +87,7 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(DBG_MOUSE_TARGET)
Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
+Q_DECLARE_LOGGING_CATEGORY(lcTransient)
void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
{
@@ -970,7 +971,7 @@ bool QQuickKeysAttached::isConnected(const char *signalName) const
Keys.onEscapePressed: {
console.log("escapeItem is handling escape");
- event.accepted = true;
+ // event.accepted is set to true by default for the specific key handlers
}
}
@@ -3264,11 +3265,13 @@ void QQuickItemPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
}
if (thisWindow) {
- if (itemWindow)
+ if (itemWindow) {
+ qCDebug(lcTransient) << thisWindow << "is transient for" << itemWindow;
thisWindow->setTransientParent(itemWindow);
- else
+ } else {
QObject::connect(item, SIGNAL(windowChanged(QQuickWindow*)),
thisWindow, SLOT(setTransientParent_helper(QQuickWindow*)));
+ }
}
o->setParent(that);
}
@@ -3667,8 +3670,9 @@ QQmlListProperty<QObject> QQuickItemPrivate::data()
\qmlproperty real QtQuick::Item::childrenRect.y
\qmlproperty real QtQuick::Item::childrenRect.width
\qmlproperty real QtQuick::Item::childrenRect.height
+ \readonly
- This property holds the collective position and size of the item's
+ This read-only property holds the collective position and size of the item's
children.
This property is useful if you need to access the collective geometry
@@ -5806,19 +5810,24 @@ bool QQuickItem::isVisible() const
return d->effectiveVisible;
}
-void QQuickItem::setVisible(bool v)
+void QQuickItemPrivate::setVisible(bool visible)
{
- Q_D(QQuickItem);
- if (v == d->explicitVisible)
+ if (visible == explicitVisible)
return;
- d->explicitVisible = v;
- if (!v)
- d->dirty(QQuickItemPrivate::Visible);
+ explicitVisible = visible;
+ if (!visible)
+ dirty(QQuickItemPrivate::Visible);
- const bool childVisibilityChanged = d->setEffectiveVisibleRecur(d->calcEffectiveVisible());
- if (childVisibilityChanged && d->parentItem)
- emit d->parentItem->visibleChildrenChanged(); // signal the parent, not this!
+ const bool childVisibilityChanged = setEffectiveVisibleRecur(calcEffectiveVisible());
+ if (childVisibilityChanged && parentItem)
+ emit parentItem->visibleChildrenChanged(); // signal the parent, not this!
+}
+
+void QQuickItem::setVisible(bool v)
+{
+ Q_D(QQuickItem);
+ d->setVisible(v);
}
/*!
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 0c02c66ef2..02e7424d1e 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -311,7 +311,6 @@ public:
static void transform_clear(QQmlListProperty<QQuickTransform> *list);
void _q_resourceObjectDeleted(QObject *);
- void _q_windowChanged(QQuickWindow *w);
quint64 _q_createJSWrapper(QV4::ExecutionEngine *engine);
enum ChangeType {
@@ -581,6 +580,8 @@ public:
virtual bool handlePointerEvent(QQuickPointerEvent *, bool avoidExclusiveGrabber = false);
+ virtual void setVisible(bool visible);
+
bool isTransparentForPositioner() const;
void setTransparentForPositioner(bool trans);
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index f03942ecee..51a91e1f7a 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -113,6 +113,10 @@
#include <private/qqmlmetatype_p.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcTransient)
+QT_END_NAMESPACE
+
static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject *parent)
{
// When setting a parent (especially during dynamic object creation) in QML,
@@ -127,6 +131,7 @@ static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject
QQuickWindow *win = qmlobject_cast<QQuickWindow *>(obj);
if (win) {
// A Window inside an Item should be transient for that item's window
+ qCDebug(lcTransient) << win << "is transient for" << parentItem->window();
win->setTransientParent(parentItem->window());
return QQmlPrivate::Parented;
}
@@ -136,6 +141,7 @@ static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject
QQuickWindow *win = qmlobject_cast<QQuickWindow *>(obj);
if (win) {
// A Window inside a Window should be transient for it
+ qCDebug(lcTransient) << win << "is transient for" << parentWindow;
win->setTransientParent(parentWindow);
return QQmlPrivate::Parented;
} else {
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 10f6c63170..856070634c 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -1751,6 +1751,7 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
void QQuickItemViewPrivate::clear()
{
currentChanges.reset();
+ bufferedChanges.reset();
timeline.clear();
releaseVisibleItems();
@@ -1808,51 +1809,56 @@ void QQuickItemViewPrivate::refill(qreal from, qreal to)
if (!isValid() || !q->isComponentComplete())
return;
- bufferPause.stop();
- currentChanges.reset();
+ do {
+ bufferPause.stop();
+ if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges()) {
+ currentChanges.reset();
+ bufferedChanges.reset();
+ releaseVisibleItems();
+ }
- int prevCount = itemCount;
- itemCount = model->count();
- qreal bufferFrom = from - buffer;
- qreal bufferTo = to + buffer;
- qreal fillFrom = from;
- qreal fillTo = to;
-
- bool added = addVisibleItems(fillFrom, fillTo, bufferFrom, bufferTo, false);
- bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
-
- if (requestedIndex == -1 && buffer && bufferMode != NoBuffer) {
- if (added) {
- // We've already created a new delegate this frame.
- // Just schedule a buffer refill.
- bufferPause.start();
- } else {
- if (bufferMode & BufferAfter)
- fillTo = bufferTo;
- if (bufferMode & BufferBefore)
- fillFrom = bufferFrom;
- added |= addVisibleItems(fillFrom, fillTo, bufferFrom, bufferTo, true);
+ int prevCount = itemCount;
+ itemCount = model->count();
+ qreal bufferFrom = from - buffer;
+ qreal bufferTo = to + buffer;
+ qreal fillFrom = from;
+ qreal fillTo = to;
+
+ bool added = addVisibleItems(fillFrom, fillTo, bufferFrom, bufferTo, false);
+ bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
+
+ if (requestedIndex == -1 && buffer && bufferMode != NoBuffer) {
+ if (added) {
+ // We've already created a new delegate this frame.
+ // Just schedule a buffer refill.
+ bufferPause.start();
+ } else {
+ if (bufferMode & BufferAfter)
+ fillTo = bufferTo;
+ if (bufferMode & BufferBefore)
+ fillFrom = bufferFrom;
+ added |= addVisibleItems(fillFrom, fillTo, bufferFrom, bufferTo, true);
+ }
}
- }
- if (added || removed) {
- markExtentsDirty();
- updateBeginningEnd();
- visibleItemsChanged();
- updateHeader();
- updateFooter();
- updateViewport();
- }
+ if (added || removed) {
+ markExtentsDirty();
+ updateBeginningEnd();
+ visibleItemsChanged();
+ updateHeader();
+ updateFooter();
+ updateViewport();
+ }
- if (prevCount != itemCount)
- emit q->countChanged();
+ if (prevCount != itemCount)
+ emit q->countChanged();
+ } while (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges());
}
void QQuickItemViewPrivate::regenerate(bool orientationChanged)
{
Q_Q(QQuickItemView);
if (q->isComponentComplete()) {
- currentChanges.reset();
if (orientationChanged) {
delete header;
header = 0;
diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h
index 3d2f5361b1..29a62f7f10 100644
--- a/src/quick/items/qquickitemviewtransition_p.h
+++ b/src/quick/items/qquickitemviewtransition_p.h
@@ -58,6 +58,8 @@ QT_REQUIRE_CONFIG(quick_viewtransitions);
#include <QtCore/qobject.h>
#include <QtCore/qpoint.h>
#include <QtQml/qqml.h>
+#include <private/qqmlguard_p.h>
+#include <private/qquicktransition_p.h>
QT_BEGIN_NAMESPACE
@@ -115,14 +117,14 @@ public:
QList<QObject *> moveTransitionTargets;
QList<QObject *> removeTransitionTargets;
- QQuickTransition *populateTransition;
- QQuickTransition *addTransition;
- QQuickTransition *addDisplacedTransition;
- QQuickTransition *moveTransition;
- QQuickTransition *moveDisplacedTransition;
- QQuickTransition *removeTransition;
- QQuickTransition *removeDisplacedTransition;
- QQuickTransition *displacedTransition;
+ QQmlGuard<QQuickTransition> populateTransition;
+ QQmlGuard<QQuickTransition> addTransition;
+ QQmlGuard<QQuickTransition> addDisplacedTransition;
+ QQmlGuard<QQuickTransition> moveTransition;
+ QQmlGuard<QQuickTransition> moveDisplacedTransition;
+ QQmlGuard<QQuickTransition> removeTransition;
+ QQmlGuard<QQuickTransition> removeDisplacedTransition;
+ QQmlGuard<QQuickTransition> displacedTransition;
private:
friend class QQuickItemViewTransitionJob;
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 11eaf393ea..54dfbafaa2 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -1468,9 +1468,6 @@ void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometry
void QQuickListViewPrivate::fixupPosition()
{
- if ((haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange)
- || snapMode != QQuickListView::NoSnap)
- moveReason = Other;
if (orient == QQuickListView::Vertical)
fixupY();
else
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 27b8d32707..d5601292b7 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -48,6 +48,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcTransient)
+
static const QQuickItemPrivate::ChangeTypes watchedChanges
= QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index 658a7de3d4..ba9460bf76 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -374,9 +374,12 @@ void QQuickRepeater::clear()
if (complete)
emit itemRemoved(i, item);
d->model->release(item);
- item->setParentItem(0);
}
}
+ for (QQuickItem *item : qAsConst(d->deletables)) {
+ if (item)
+ item->setParentItem(0);
+ }
}
d->deletables.clear();
d->itemCount = 0;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index cfeaa6f22d..2e36f07fdb 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -78,6 +78,9 @@
# include <private/qopenglvertexarrayobject_p.h>
# include <private/qsgdefaultrendercontext_p.h>
#endif
+#ifndef QT_NO_DEBUG_STREAM
+#include <private/qdebug_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -88,6 +91,7 @@ Q_LOGGING_CATEGORY(DBG_MOUSE_TARGET, "qt.quick.mouse.target")
Q_LOGGING_CATEGORY(DBG_HOVER_TRACE, "qt.quick.hover.trace")
Q_LOGGING_CATEGORY(DBG_FOCUS, "qt.quick.focus")
Q_LOGGING_CATEGORY(DBG_DIRTY, "qt.quick.dirty")
+Q_LOGGING_CATEGORY(lcTransient, "qt.quick.window.transient")
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
@@ -576,13 +580,21 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
QObject::connect(q, SIGNAL(focusObjectChanged(QObject*)), q, SIGNAL(activeFocusItemChanged()));
QObject::connect(q, SIGNAL(screenChanged(QScreen*)), q, SLOT(handleScreenChanged(QScreen*)));
-
+ QObject::connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
+ q, SLOT(handleApplicationStateChanged(Qt::ApplicationState)));
QObject::connect(q, SIGNAL(frameSwapped()), q, SLOT(runJobsAfterSwap()), Qt::DirectConnection);
if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
service->addWindow(q);
}
+void QQuickWindow::handleApplicationStateChanged(Qt::ApplicationState state)
+{
+ Q_D(QQuickWindow);
+ if (state != Qt::ApplicationActive && d->contentItem)
+ d->contentItem->windowDeactivateEvent();
+}
+
/*!
\property QQuickWindow::data
\internal
@@ -2280,6 +2292,7 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) con
void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event)
{
+ Q_Q(QQuickWindow);
// If users spin the eventloop as a result of event delivery, we disable
// event compression and send events directly. This is because we consider
// the usecase a bit evil, but we at least don't want to lose events.
@@ -2289,8 +2302,11 @@ void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event)
if (event->asPointerMouseEvent()) {
deliverMouseEvent(event->asPointerMouseEvent());
// failsafe: never allow any kind of grab to persist after release
- if (event->isReleaseEvent() && event->buttons() == Qt::NoButton)
+ QQuickItem *grabber = q->mouseGrabberItem();
+ if (event->isReleaseEvent() && event->buttons() == Qt::NoButton && grabber) {
event->clearGrabbers();
+ sendUngrabEvent(grabber, false);
+ }
} else if (event->asPointerTouchEvent()) {
deliverTouchEvent(event->asPointerTouchEvent());
} else {
@@ -2961,8 +2977,10 @@ void QQuickWindowPrivate::data_append(QQmlListProperty<QObject> *property, QObje
if (!o)
return;
QQuickWindow *that = static_cast<QQuickWindow *>(property->object);
- if (QQuickWindow *window = qmlobject_cast<QQuickWindow *>(o))
+ if (QQuickWindow *window = qmlobject_cast<QQuickWindow *>(o)) {
+ qCDebug(lcTransient) << window << "is transient for" << that;
window->setTransientParent(that);
+ }
QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(that->contentItem())->data();
itemProperty.append(&itemProperty, o);
}
@@ -3493,6 +3511,7 @@ void QQuickWindow::cleanupSceneGraph()
void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
{
+ qCDebug(lcTransient) << this << "is transient for" << window;
setTransientParent(window);
disconnect(sender(), SIGNAL(windowChanged(QQuickWindow*)),
this, SLOT(setTransientParent_helper(QQuickWindow*)));
@@ -4935,6 +4954,37 @@ void QQuickWindow::setTextRenderType(QQuickWindow::TextRenderType renderType)
QQuickWindowPrivate::textRenderType = renderType;
}
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QQuickWindow *win)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ if (!win) {
+ debug << "QQuickWindow(0)";
+ return debug;
+ }
+
+ debug << win->metaObject()->className() << '(' << static_cast<const void *>(win);
+ if (win->isActive())
+ debug << " active";
+ if (win->isExposed())
+ debug << " exposed";
+ debug << ", visibility=" << win->visibility() << ", flags=" << win->flags();
+ if (!win->title().isEmpty())
+ debug << ", title=" << win->title();
+ if (!win->objectName().isEmpty())
+ debug << ", name=" << win->objectName();
+ if (win->parent())
+ debug << ", parent=" << static_cast<const void *>(win->parent());
+ if (win->transientParent())
+ debug << ", transientParent=" << static_cast<const void *>(win->transientParent());
+ debug << ", geometry=";
+ QtDebugUtils::formatQRect(debug, win->geometry());
+ debug << ')';
+ return debug;
+}
+#endif
+
#include "moc_qquickwindow.cpp"
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 06af7bbf02..53e0581fbb 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -234,7 +234,7 @@ private Q_SLOTS:
void handleScreenChanged(QScreen *screen);
void setTransientParent_helper(QQuickWindow *window);
void runJobsAfterSwap();
-
+ void handleApplicationStateChanged(Qt::ApplicationState state);
private:
friend class QQuickItem;
friend class QQuickWidget;
@@ -243,6 +243,10 @@ private:
Q_DISABLE_COPY(QQuickWindow)
};
+#ifndef QT_NO_DEBUG_STREAM
+QDebug Q_QUICK_EXPORT operator<<(QDebug debug, const QQuickWindow *item);
+#endif
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQuickWindow *)
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index 45e3f0004d..6165ce1ba1 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -52,6 +52,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcTransient)
+
class QQuickWindowQmlImplPrivate : public QQuickWindowPrivate
{
public:
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
index 30088846a6..4cec84646e 100644
--- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
@@ -233,11 +233,11 @@ void QSGAbstractSoftwareRenderer::setBackgroundColor(const QColor &color)
renderableNode(m_background)->markMaterialDirty();
}
-void QSGAbstractSoftwareRenderer::setBackgroundSize(const QSize &size)
+void QSGAbstractSoftwareRenderer::setBackgroundRect(const QRect &rect)
{
- if (m_background->rect().size().toSize() == size)
+ if (m_background->rect().toRect() == rect)
return;
- m_background->setRect(0.0f, 0.0f, size.width(), size.height());
+ m_background->setRect(rect);
renderableNode(m_background)->markGeometryDirty();
// Invalidate the whole scene when the background is resized
markDirty();
@@ -248,9 +248,9 @@ QColor QSGAbstractSoftwareRenderer::backgroundColor()
return m_background->color();
}
-QSize QSGAbstractSoftwareRenderer::backgroundSize()
+QRect QSGAbstractSoftwareRenderer::backgroundRect()
{
- return m_background->rect().size().toSize();
+ return m_background->rect().toRect();
}
void QSGAbstractSoftwareRenderer::nodeAdded(QSGNode *node)
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
index f20c2cf977..f6594d931a 100644
--- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
@@ -83,9 +83,9 @@ protected:
QRegion optimizeRenderList();
void setBackgroundColor(const QColor &color);
- void setBackgroundSize(const QSize &size);
+ void setBackgroundRect(const QRect &rect);
QColor backgroundColor();
- QSize backgroundSize();
+ QRect backgroundRect();
// only known after calling optimizeRenderList()
bool isOpaque() const { return m_isOpaque; }
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
index 186fd92fb7..303f98c801 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
@@ -79,7 +79,7 @@ void QSGSoftwarePixmapRenderer::render(QPaintDevice *target)
QElapsedTimer renderTimer;
// Setup background item
- setBackgroundSize(QSize(target->width(), target->height()));
+ setBackgroundRect(m_projectionRect);
setBackgroundColor(clearColor());
renderTimer.start();
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
index 85d04fe136..d403884b4e 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
@@ -112,7 +112,8 @@ void QSGSoftwareRenderer::render()
QElapsedTimer renderTimer;
setBackgroundColor(clearColor());
- setBackgroundSize(QSize(m_paintDevice->width() / m_paintDevice->devicePixelRatio(),
+ setBackgroundRect(QRect(0, 0,
+ m_paintDevice->width() / m_paintDevice->devicePixelRatio(),
m_paintDevice->height() / m_paintDevice->devicePixelRatio()));
// Build Renderlist
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
index a67c659c99..03c5738e56 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -203,7 +203,7 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q
updateTextureScale(QVector2D(1.0 / material->textureSize().width(),
1.0 / material->textureSize().height()));
- QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ QOpenGLFunctions *funcs = state.context()->functions();
funcs->glBindTexture(GL_TEXTURE_2D, material->texture()->textureId);
if (updated) {
diff --git a/src/quick/util/qquickanimationcontroller.cpp b/src/quick/util/qquickanimationcontroller.cpp
index cebb0391ae..5e56460098 100644
--- a/src/quick/util/qquickanimationcontroller.cpp
+++ b/src/quick/util/qquickanimationcontroller.cpp
@@ -223,7 +223,7 @@ void QQuickAnimationController::updateProgress()
d->animationInstance->setDisableUserControl();
d->animationInstance->start();
- QQmlAnimationTimer::unregisterAnimation(d->animationInstance);
+ QQmlAnimationTimer::instance()->unregisterAnimation(d->animationInstance);
d->animationInstance->setCurrentTime(d->progress * d->animationInstance->duration());
}
diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp
index 4a9b4a95c1..b3f4faea3f 100644
--- a/src/quick/util/qquickpropertychanges.cpp
+++ b/src/quick/util/qquickpropertychanges.cpp
@@ -281,15 +281,19 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
return;
}
- QQmlProperty prop = property(propertyName); //### better way to check for signal property?
-
- if (prop.type() & QQmlProperty::SignalProperty) {
- QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
- handler->property = prop;
- handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(),
- QQmlContextData::get(qmlContext(q)), object, compilationUnit->runtimeFunctions.at(binding->value.compiledScriptIndex)));
- signalReplacements << handler;
- return;
+ if (propertyName.count() >= 3 &&
+ propertyName.at(0) == QLatin1Char('o') &&
+ propertyName.at(1) == QLatin1Char('n') &&
+ propertyName.at(2).isUpper()) {
+ QQmlProperty prop = property(propertyName);
+ if (prop.isSignalProperty()) {
+ QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
+ handler->property = prop;
+ handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(),
+ QQmlContextData::get(qmlContext(q)), object, compilationUnit->runtimeFunctions.at(binding->value.compiledScriptIndex)));
+ signalReplacements << handler;
+ return;
+ }
}
if (binding->type == QV4::CompiledData::Binding::Type_Script) {
@@ -395,7 +399,10 @@ QQmlProperty
QQuickPropertyChangesPrivate::property(const QString &property)
{
Q_Q(QQuickPropertyChanges);
- QQmlProperty prop(object, property, qmlContext(q));
+ QQmlContextData *context = nullptr;
+ if (QQmlData *ddata = QQmlData::get(q))
+ context = ddata->outerContext;
+ QQmlProperty prop = QQmlPropertyPrivate::create(object, property, context);
if (!prop.isValid()) {
qmlWarning(q) << QQuickPropertyChanges::tr("Cannot assign to non-existent property \"%1\"").arg(property);
return QQmlProperty();
@@ -415,9 +422,10 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
ActionList list;
for (int ii = 0; ii < d->properties.count(); ++ii) {
+ QQmlProperty prop = d->property(d->properties.at(ii).first);
- QQuickStateAction a(d->object, d->properties.at(ii).first,
- qmlContext(this), d->properties.at(ii).second);
+ QQuickStateAction a(d->object, prop, d->properties.at(ii).first,
+ d->properties.at(ii).second);
if (a.property.isValid()) {
a.restore = restoreEntryValues();
@@ -426,7 +434,6 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
}
for (int ii = 0; ii < d->signalReplacements.count(); ++ii) {
-
QQuickReplaceSignalHandler *handler = d->signalReplacements.at(ii);
if (handler->property.isValid()) {
diff --git a/src/quick/util/qquickshortcut.cpp b/src/quick/util/qquickshortcut.cpp
index 58f7fc8439..78dc855326 100644
--- a/src/quick/util/qquickshortcut.cpp
+++ b/src/quick/util/qquickshortcut.cpp
@@ -122,7 +122,8 @@ Q_QUICK_PRIVATE_EXPORT ContextMatcher qt_quick_shortcut_context_matcher()
Q_QUICK_PRIVATE_EXPORT void qt_quick_set_shortcut_context_matcher(ContextMatcher matcher)
{
- *ctxMatcher() = matcher;
+ if (!ctxMatcher.isDestroyed())
+ *ctxMatcher() = matcher;
}
QT_BEGIN_NAMESPACE
diff --git a/src/quick/util/qquickstate.cpp b/src/quick/util/qquickstate.cpp
index 65e51feb81..3e0a2169a8 100644
--- a/src/quick/util/qquickstate.cpp
+++ b/src/quick/util/qquickstate.cpp
@@ -68,10 +68,9 @@ QQuickStateAction::QQuickStateAction(QObject *target, const QString &propertyNam
fromValue = property.read();
}
-QQuickStateAction::QQuickStateAction(QObject *target, const QString &propertyName,
- QQmlContext *context, const QVariant &value)
+QQuickStateAction::QQuickStateAction(QObject *target, const QQmlProperty &property, const QString &propertyName, const QVariant &value)
: restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false),
- property(target, propertyName, context), toValue(value),
+ property(property), toValue(value),
fromBinding(0), event(0),
specifiedObject(target), specifiedProperty(propertyName)
{
diff --git a/src/quick/util/qquickstate_p.h b/src/quick/util/qquickstate_p.h
index ac720f4189..f551402e80 100644
--- a/src/quick/util/qquickstate_p.h
+++ b/src/quick/util/qquickstate_p.h
@@ -69,8 +69,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickStateAction
public:
QQuickStateAction();
QQuickStateAction(QObject *, const QString &, const QVariant &);
- QQuickStateAction(QObject *, const QString &,
- QQmlContext *, const QVariant &);
+ QQuickStateAction(QObject *, const QQmlProperty &property, const QString &,
+ const QVariant &);
bool restore:1;
bool actionDone:1;
diff --git a/src/quick/util/qquicktransition.cpp b/src/quick/util/qquicktransition.cpp
index 29690a4857..6ae89c4ed4 100644
--- a/src/quick/util/qquicktransition.cpp
+++ b/src/quick/util/qquicktransition.cpp
@@ -109,7 +109,7 @@ protected:
void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState) override;
};
-class QQuickTransitionPrivate : public QObjectPrivate, QAnimationJobChangeListener
+class QQuickTransitionPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQuickTransition)
public:
@@ -120,11 +120,8 @@ public:
{
}
- void removeStateChangeListener(QAbstractAnimationJob *anim)
- {
- if (anim)
- anim->removeAnimationChangeListener(this, QAbstractAnimationJob::StateChange);
- }
+ static QQuickTransitionPrivate *get(QQuickTransition *q) { return q->d_func(); }
+ void animationStateChanged(QAbstractAnimationJob::State newState);
QString fromState;
QString toState;
@@ -134,7 +131,6 @@ public:
bool reversible;
bool enabled;
protected:
- void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State, QAbstractAnimationJob::State) override;
static void append_animation(QQmlListProperty<QQuickAbstractAnimation> *list, QQuickAbstractAnimation *a);
static int animation_count(QQmlListProperty<QQuickAbstractAnimation> *list);
@@ -171,7 +167,16 @@ void QQuickTransitionPrivate::clear_animations(QQmlListProperty<QQuickAbstractAn
}
}
-void QQuickTransitionPrivate::animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State)
+void QQuickTransitionInstance::animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State)
+{
+ if (!m_transition)
+ return;
+
+ QQuickTransitionPrivate *transition = QQuickTransitionPrivate::get(m_transition);
+ transition->animationStateChanged(newState);
+}
+
+void QQuickTransitionPrivate::animationStateChanged(QAbstractAnimationJob::State newState)
{
Q_Q(QQuickTransition);
@@ -197,15 +202,16 @@ void ParallelAnimationWrapper::updateState(QAbstractAnimationJob::State newState
}
}
-QQuickTransitionInstance::QQuickTransitionInstance(QQuickTransitionPrivate *transition, QAbstractAnimationJob *anim)
+QQuickTransitionInstance::QQuickTransitionInstance(QQuickTransition *transition, QAbstractAnimationJob *anim)
: m_transition(transition)
, m_anim(anim)
{
+ anim->addAnimationChangeListener(this, QAbstractAnimationJob::StateChange);
}
QQuickTransitionInstance::~QQuickTransitionInstance()
{
- m_transition->removeStateChangeListener(m_anim);
+ removeStateChangeListener();
delete m_anim;
}
@@ -270,8 +276,7 @@ QQuickTransitionInstance *QQuickTransition::prepare(QQuickStateOperation::Action
group->setDirection(d->reversed ? QAbstractAnimationJob::Backward : QAbstractAnimationJob::Forward);
- group->addAnimationChangeListener(d, QAbstractAnimationJob::StateChange);
- QQuickTransitionInstance *wrapper = new QQuickTransitionInstance(d, group);
+ QQuickTransitionInstance *wrapper = new QQuickTransitionInstance(this, group);
return wrapper;
}
diff --git a/src/quick/util/qquicktransition_p.h b/src/quick/util/qquicktransition_p.h
index d6f365f99e..6d2e41fc9d 100644
--- a/src/quick/util/qquicktransition_p.h
+++ b/src/quick/util/qquicktransition_p.h
@@ -53,6 +53,7 @@
#include "qquickstate_p.h"
#include <private/qabstractanimationjob_p.h>
+#include <private/qqmlguard_p.h>
#include <qqml.h>
#include <QtCore/qobject.h>
@@ -64,10 +65,10 @@ class QQuickTransitionPrivate;
class QQuickTransitionManager;
class QQuickTransition;
-class QQuickTransitionInstance
+class QQuickTransitionInstance : QAnimationJobChangeListener
{
public:
- QQuickTransitionInstance(QQuickTransitionPrivate *transition, QAbstractAnimationJob *anim);
+ QQuickTransitionInstance(QQuickTransition *transition, QAbstractAnimationJob *anim);
~QQuickTransitionInstance();
void start();
@@ -75,8 +76,16 @@ public:
bool isRunning() const;
+protected:
+ void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State, QAbstractAnimationJob::State) override;
+
+ void removeStateChangeListener()
+ {
+ m_anim->removeAnimationChangeListener(this, QAbstractAnimationJob::StateChange);
+ }
+
private:
- QQuickTransitionPrivate *m_transition;
+ QQmlGuard<QQuickTransition> m_transition;
QAbstractAnimationJob *m_anim;
friend class QQuickTransition;
};
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index cdde3b980f..00aec0113c 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -935,7 +935,7 @@ void QQuickWidget::createFramebufferObject()
}
QOpenGLContext *shareWindowContext = QWidgetPrivate::get(window())->shareContext();
- if (shareWindowContext && context->shareContext() != shareWindowContext) {
+ if (shareWindowContext && context->shareContext() != shareWindowContext && !qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)) {
context->setShareContext(shareWindowContext);
context->setScreen(shareWindowContext->screen());
if (!context->create())
@@ -1247,11 +1247,11 @@ void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove, e->localPos().x(),
e->localPos().y());
- // Use the constructor taking localPos and screenPos. That puts localPos into the
- // event's localPos and windowPos, and screenPos into the event's screenPos. This way
- // the windowPos in e is ignored and is replaced by localPos. This is necessary
- // because QQuickWindow thinks of itself as a top-level window always.
- QMouseEvent mappedEvent(e->type(), e->localPos(), e->windowPos(), e->screenPos(),
+ // Put localPos into the event's localPos and windowPos, and screenPos into the
+ // event's screenPos. This way the windowPos in e is ignored and is replaced by
+ // localPos. This is necessary because QQuickWindow thinks of itself as a
+ // top-level window always.
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->localPos(), e->screenPos(),
e->button(), e->buttons(), e->modifiers(), e->source());
QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
e->setAccepted(mappedEvent.isAccepted());
@@ -1266,11 +1266,11 @@ void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
// As the second mouse press is suppressed in widget windows we emulate it here for QML.
// See QTBUG-25831
- QMouseEvent pressEvent(QEvent::MouseButtonPress, e->localPos(), e->windowPos(), e->screenPos(),
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, e->localPos(), e->localPos(), e->screenPos(),
e->button(), e->buttons(), e->modifiers(), e->source());
QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
e->setAccepted(pressEvent.isAccepted());
- QMouseEvent mappedEvent(e->type(), e->localPos(), e->windowPos(), e->screenPos(),
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->localPos(), e->screenPos(),
e->button(), e->buttons(), e->modifiers(), e->source());
QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
}
@@ -1331,7 +1331,7 @@ void QQuickWidget::mousePressEvent(QMouseEvent *e)
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, e->button(),
e->buttons());
- QMouseEvent mappedEvent(e->type(), e->localPos(), e->windowPos(), e->screenPos(),
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->localPos(), e->screenPos(),
e->button(), e->buttons(), e->modifiers(), e->source());
QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
e->setAccepted(mappedEvent.isAccepted());
@@ -1344,7 +1344,7 @@ void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, e->button(),
e->buttons());
- QMouseEvent mappedEvent(e->type(), e->localPos(), e->windowPos(), e->screenPos(),
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->localPos(), e->screenPos(),
e->button(), e->buttons(), e->modifiers(), e->source());
QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
e->setAccepted(mappedEvent.isAccepted());
@@ -1395,6 +1395,28 @@ static Qt::WindowState resolveWindowState(Qt::WindowStates states)
return Qt::WindowNoState;
}
+static void remapInputMethodQueryEvent(QObject *object, QInputMethodQueryEvent *e)
+{
+ auto item = qobject_cast<QQuickItem *>(object);
+ if (!item)
+ return;
+
+ // Remap all QRectF values.
+ for (auto query : {Qt::ImCursorRectangle, Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle}) {
+ if (e->queries() & query) {
+ auto value = e->value(query);
+ if (value.canConvert<QRectF>())
+ e->setValue(query, item->mapRectToScene(value.toRectF()));
+ }
+ }
+ // Remap all QPointF values.
+ if (e->queries() & Qt::ImCursorPosition) {
+ auto value = e->value(Qt::ImCursorPosition);
+ if (value.canConvert<QPointF>())
+ e->setValue(Qt::ImCursorPosition, item->mapToScene(value.toPointF()));
+ }
+}
+
/*! \reimp */
bool QQuickWidget::event(QEvent *e)
{
@@ -1411,8 +1433,17 @@ bool QQuickWidget::event(QEvent *e)
return QCoreApplication::sendEvent(d->offscreenWindow, e);
case QEvent::InputMethod:
- case QEvent::InputMethodQuery:
return QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
+ case QEvent::InputMethodQuery:
+ {
+ bool eventResult = QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
+ // The result in focusObject are based on offscreenWindow. But
+ // the inputMethodTransform won't get updated because the focus
+ // is on QQuickWidget. We need to remap the value based on the
+ // widget.
+ remapInputMethodQueryEvent(d->offscreenWindow->focusObject(), static_cast<QInputMethodQueryEvent *>(e));
+ return eventResult;
+ }
case QEvent::WindowChangeInternal:
d->handleWindowChange();
diff --git a/tests/auto/particles/qquickcustomaffector/BLACKLIST b/tests/auto/particles/qquickcustomaffector/BLACKLIST
new file mode 100644
index 0000000000..0757641bcc
--- /dev/null
+++ b/tests/auto/particles/qquickcustomaffector/BLACKLIST
@@ -0,0 +1,2 @@
+[test_move]
+windows gcc developer-build
diff --git a/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp b/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp
index ee05fb29c9..cad3813e92 100644
--- a/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp
+++ b/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp
@@ -98,16 +98,17 @@ void tst_qquickcustomaffector::test_move()
if (!d->stillAlive(system))
continue; //parameters no longer get set once you die
- QVERIFY(myFuzzyCompare(d->curX(system), 50.0));
- QVERIFY(myFuzzyCompare(d->curY(system), 50.0));
- QVERIFY(myFuzzyCompare(d->curVX(system), 50.0));
- QVERIFY(myFuzzyCompare(d->curVY(system), 50.0));
- QVERIFY(myFuzzyCompare(d->curAX(), 50.0));
- QVERIFY(myFuzzyCompare(d->curAY(), 50.0));
+ QVERIFY2(myFuzzyCompare(d->curX(system), 50.0), QByteArray::number(d->curX(system)));
+ QVERIFY2(myFuzzyCompare(d->curY(system), 50.0), QByteArray::number(d->curY(system)));
+ QVERIFY2(myFuzzyCompare(d->curVX(system), 50.0), QByteArray::number(d->curVX(system)));
+ QVERIFY2(myFuzzyCompare(d->curVY(system), 50.0), QByteArray::number(d->curVY(system)));
+ QVERIFY2(myFuzzyCompare(d->curAX(), 50.0), QByteArray::number(d->curAX()));
+ QVERIFY2(myFuzzyCompare(d->curAY(), 50.0), QByteArray::number(d->curAY()));
QCOMPARE(d->lifeSpan, 0.5f);
QCOMPARE(d->size, 32.f);
QCOMPARE(d->endSize, 32.f);
- QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0)));
+ QVERIFY2(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0)),
+ QString::fromLatin1("%1 <= %2 / 1000").arg(d->t).arg(system->timeInt).toUtf8());
}
delete view;
}
diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
index bdd691732a..8993ce7cf4 100644
--- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
+++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
@@ -910,7 +910,8 @@ void tst_QQmlEngineDebugService::queryObjectWithNonStreamableTypes()
QmlDebugObjectReference obj = m_dbg->object();
QVERIFY(!obj.className.isEmpty());
- QCOMPARE(findProperty(obj.properties, "modelIndex").value, QVariant());
+ QCOMPARE(findProperty(obj.properties, "modelIndex").value,
+ QVariant(QLatin1String("QModelIndex()")));
}
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 8471d6466f..9557393a2e 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -9,6 +9,7 @@ PUBLICTESTS += \
qjsvalueiterator \
qjsonbinding \
qqmlfile \
+ qqmlfileselector
PUBLICTESTS += \
qmlmin \
diff --git a/tests/auto/qml/qmlplugindump/qmlplugindump.pro b/tests/auto/qml/qmlplugindump/qmlplugindump.pro
index 76f3fe2299..ab915c819c 100644
--- a/tests/auto/qml/qmlplugindump/qmlplugindump.pro
+++ b/tests/auto/qml/qmlplugindump/qmlplugindump.pro
@@ -1,8 +1,7 @@
-CONFIG += testcase
-TARGET = tst_qmlplugindump
QT += testlib gui-private qml
macx:CONFIG -= app_bundle
include(../../shared/util.pri)
+DEFINES += QT_QMLTEST_DIR=\\\"$${_PRO_FILE_PWD_}\\\"
SOURCES += tst_qmlplugindump.cpp
diff --git a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
index 6915e789c6..ffddc52f9c 100644
--- a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
+++ b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
@@ -105,8 +105,8 @@ void tst_qmlplugindump::singleton()
{
QProcess dumper;
QStringList args;
- args << QLatin1String("dumper.CompositeSingleton") << QLatin1String("1.0")
- << testFile(".");
+ args << QLatin1String("tests.dumper.CompositeSingleton") << QLatin1String("1.0")
+ << QLatin1String(QT_QMLTEST_DIR);
dumper.start(qmlplugindumpPath, args);
QVERIFY2(dumper.waitForStarted(), qPrintable(dumper.errorString()));
QVERIFY2(dumper.waitForFinished(), qPrintable(dumper.errorString()));
diff --git a/tests/auto/qml/qqmlcomponent/data/QtObjectComponent#2.qml b/tests/auto/qml/qqmlcomponent/data/QtObjectComponent#2.qml
new file mode 100644
index 0000000000..431c659424
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/QtObjectComponent#2.qml
@@ -0,0 +1,3 @@
+import QtQml 2.0
+
+QtObject {}
diff --git a/tests/auto/qml/qqmlcomponent/data/QtObjectComponent.qml b/tests/auto/qml/qqmlcomponent/data/QtObjectComponent.qml
new file mode 100644
index 0000000000..431c659424
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/QtObjectComponent.qml
@@ -0,0 +1,3 @@
+import QtQml 2.0
+
+QtObject {}
diff --git a/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro b/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro
index a74334ef63..54012e050c 100644
--- a/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro
+++ b/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro
@@ -7,6 +7,8 @@ SOURCES += tst_qqmlcomponent.cpp \
HEADERS += ../../shared/testhttpserver.h
+RESOURCES += data/QtObjectComponent.qml
+
include (../../shared/util.pri)
TESTDATA = data/*
diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
index f2b0b9973e..3c78f6601e 100644
--- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
+++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
@@ -117,6 +117,8 @@ private slots:
void recursion();
void recursionContinuation();
void callingContextForInitialProperties();
+ void relativeUrl_data();
+ void relativeUrl();
private:
QQmlEngine engine;
@@ -581,6 +583,28 @@ void tst_qqmlcomponent::callingContextForInitialProperties()
QVERIFY(checker->scopeObject->metaObject()->indexOfProperty("incubatedObject") != -1);
}
+void tst_qqmlcomponent::relativeUrl_data()
+{
+ QTest::addColumn<QUrl>("url");
+
+ QTest::addRow("fromLocalFile") << QUrl::fromLocalFile("data/QtObjectComponent.qml");
+ QTest::addRow("fromLocalFileHash") << QUrl::fromLocalFile("data/QtObjectComponent#2.qml");
+ QTest::addRow("constructor") << QUrl("data/QtObjectComponent.qml");
+ QTest::addRow("absolute") << QUrl::fromLocalFile(QFINDTESTDATA("data/QtObjectComponent.qml"));
+ QTest::addRow("qrc") << QUrl("qrc:/data/QtObjectComponent.qml");
+}
+
+void tst_qqmlcomponent::relativeUrl()
+{
+ QFETCH(QUrl, url);
+
+ QQmlComponent component(&engine);
+ // Shouldn't assert in QQmlTypeLoader; we want QQmlComponent to assume that
+ // data/QtObjectComponent.qml refers to the data/QtObjectComponent.qml in the current working directory.
+ component.loadUrl(url);
+ QVERIFY2(!component.isError(), qPrintable(component.errorString()));
+}
+
QTEST_MAIN(tst_qqmlcomponent)
#include "tst_qqmlcomponent.moc"
diff --git a/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp b/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp
index 648e4490ee..2c62353630 100644
--- a/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp
+++ b/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp
@@ -33,6 +33,7 @@
#include <QQmlApplicationEngine>
#include <QFileSelector>
#include <QQmlContext>
+#include <QLoggingCategory>
#include <qqmlinfo.h>
#include "../../shared/util.h"
@@ -44,6 +45,7 @@ public:
private slots:
void basicTest();
+ void basicTestCached();
void applicationEngineTest();
};
@@ -62,6 +64,25 @@ void tst_qqmlfileselector::basicTest()
delete object;
}
+void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+{
+ if (type == QtDebugMsg
+ && QByteArray(context.category) == QByteArray("qt.qml.diskcache")
+ && message.contains("QML source file has moved to a different location.")) {
+ QFAIL(message.toUtf8());
+ }
+}
+
+void tst_qqmlfileselector::basicTestCached()
+{
+ basicTest(); // Seed the cache, in case basicTestCached() is run on its own
+ QtMessageHandler defaultHandler = qInstallMessageHandler(&messageHandler);
+ QLoggingCategory::setFilterRules("qt.qml.diskcache.debug=true");
+ basicTest(); // Run again and check that the file is in the cache now
+ QLoggingCategory::setFilterRules(QString());
+ qInstallMessageHandler(defaultHandler);
+}
+
void tst_qqmlfileselector::applicationEngineTest()
{
QQmlApplicationEngine engine;
diff --git a/tests/auto/qml/qqmllanguage/data/accessDeletedObject.qml b/tests/auto/qml/qqmllanguage/data/accessDeletedObject.qml
new file mode 100644
index 0000000000..e5151096e5
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/accessDeletedObject.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ Component.onCompleted: {
+ var createdObject = objectCreator.create()
+ createdObject.del()
+ // Shouldn't crash.
+ var test = "index" in createdObject
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.12.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidAlias.12.errors.txt
new file mode 100644
index 0000000000..8b94763860
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.12.errors.txt
@@ -0,0 +1 @@
+4:28:Invalid alias target location: source
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.12.qml b/tests/auto/qml/qqmllanguage/data/invalidAlias.12.qml
new file mode 100644
index 0000000000..71063ae320
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.12.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+QtObject {
+ property alias source: previewImage.source
+ previewImage { id: previewImage }
+}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index a56318f80c..dfc6509732 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -277,6 +277,8 @@ private slots:
void concurrentLoadQmlDir();
+ void accessDeletedObject();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -518,6 +520,7 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("invalidAlias.9") << "invalidAlias.9.qml" << "invalidAlias.9.errors.txt" << false;
QTest::newRow("invalidAlias.10") << "invalidAlias.10.qml" << "invalidAlias.10.errors.txt" << false;
QTest::newRow("invalidAlias.11") << "invalidAlias.11.qml" << "invalidAlias.11.errors.txt" << false;
+ QTest::newRow("invalidAlias.12") << "invalidAlias.12.qml" << "invalidAlias.12.errors.txt" << false;
QTest::newRow("invalidAttachedProperty.1") << "invalidAttachedProperty.1.qml" << "invalidAttachedProperty.1.errors.txt" << false;
QTest::newRow("invalidAttachedProperty.2") << "invalidAttachedProperty.2.qml" << "invalidAttachedProperty.2.errors.txt" << false;
@@ -4877,6 +4880,28 @@ void tst_qqmllanguage::concurrentLoadQmlDir()
engine.setImportPathList(defaultImportPathList);
}
+// Test that deleting an object and then accessing it doesn't crash.
+// QTBUG-44153
+class ObjectCreator : public QObject
+{
+ Q_OBJECT
+public slots:
+ QObject *create() { return (new ObjectCreator); }
+ void del() { delete this; }
+};
+
+void tst_qqmllanguage::accessDeletedObject()
+{
+ QQmlEngine engine;
+
+ engine.rootContext()->setContextProperty("objectCreator", new ObjectCreator);
+ QQmlComponent component(&engine, testFileUrl("accessDeletedObject.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmltypeloader/data/ComponentWithIncubator.qml b/tests/auto/qml/qqmltypeloader/data/ComponentWithIncubator.qml
new file mode 100644
index 0000000000..b3610831df
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/ComponentWithIncubator.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ Repeater {
+ model: 3
+ Item {}
+ }
+}
+
diff --git a/tests/auto/qml/qqmltypeloader/data/trim_cache3.qml b/tests/auto/qml/qqmltypeloader/data/trim_cache3.qml
new file mode 100644
index 0000000000..219c7d3bcb
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/trim_cache3.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Item {
+ width: 400
+ height: 400
+
+ property alias source: loader.source
+
+ Loader {
+ id: loader
+ source: "ComponentWithIncubator.qml"
+ }
+}
+
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index 5ab729042f..5a3d76e903 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -44,6 +44,7 @@ private slots:
void loadComponentSynchronously();
void trimCache();
void trimCache2();
+ void trimCache3();
void keepSingleton();
void keepRegistrations();
void intercept();
@@ -124,6 +125,26 @@ void tst_QQMLTypeLoader::trimCache2()
QCOMPARE(loader.isTypeLoaded(testFileUrl("MyComponent2.qml")), false);
}
+// test trimming the cache of an item that contains sub-items created via incubation
+void tst_QQMLTypeLoader::trimCache3()
+{
+ QScopedPointer<QQuickView> window(new QQuickView());
+ window->setSource(testFileUrl("trim_cache3.qml"));
+ QQmlTypeLoader &loader = QQmlEnginePrivate::get(window->engine())->typeLoader;
+ QCOMPARE(loader.isTypeLoaded(testFileUrl("ComponentWithIncubator.qml")), true);
+
+ QQmlProperty::write(window->rootObject(), "source", QString());
+
+ // handle our deleteLater and cleanup
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ window->engine()->collectGarbage();
+
+ window->engine()->trimComponentCache();
+
+ QCOMPARE(loader.isTypeLoaded(testFileUrl("ComponentWithIncubator.qml")), false);
+}
+
static void checkSingleton(const QString &dataDirectory)
{
QQmlEngine engine;
diff --git a/tests/auto/quick/qquickgridview/data/qtbug49218.qml b/tests/auto/quick/qquickgridview/data/qtbug49218.qml
new file mode 100644
index 0000000000..1a55fe5b3a
--- /dev/null
+++ b/tests/auto/quick/qquickgridview/data/qtbug49218.qml
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+Item {
+ width: 500
+ height: 160
+ visible: true
+
+ property var model1: ["1","2","3","4","5","6","7","8","9","10",
+ "11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30",
+ "31","32","33","34","a"]
+ property var model2: ["a","b","c","d","e","f","g","h","i","j","k","l","m","1"]
+ property bool useModel1: true
+
+ function changeModel() {
+ useModel1 = !useModel1
+ grid.loadModel(useModel1 ? model1 : model2)
+ }
+
+ function scrollToTop() {
+ grid.contentY = grid.originY;
+ }
+
+ GridView {
+ id: grid
+ anchors.fill: parent
+
+ model: ListModel {
+ }
+
+ onCurrentIndexChanged: {
+ positionViewAtIndex(currentIndex, GridView.Contain)
+ }
+
+ Component.onCompleted: {
+ loadModel(model1)
+ grid.currentIndex = 34
+ grid.positionViewAtIndex(34, GridView.Contain)
+ }
+
+ function loadModel(m) {
+ var remove = {};
+ var add = {};
+ var i;
+ for (i=0; i < model.count; ++i)
+ remove[model.get(i).name] = true;
+ for (i=0; i < m.length; ++i)
+ if (remove[m[i]])
+ delete remove[m[i]];
+ else
+ add[m[i]] = true;
+
+ for (i=model.count-1; i>= 0; --i)
+ if (remove[model.get(i).name])
+ model.remove(i, 1);
+
+ for (i=0; i<m.length; ++i)
+ if (add[m[i]])
+ model.insert(i, { "name": m[i] })
+ }
+
+ delegate: Rectangle {
+ height: grid.cellHeight
+ width: grid.cellWidth
+ color: GridView.isCurrentItem ? "gray" : "white"
+ Text {
+ anchors.fill: parent
+ text: name
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ grid.currentIndex = index
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
index 2a4a9dbdd9..ce04dc3c80 100644
--- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
+++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
@@ -210,6 +210,7 @@ private slots:
void contentHeightWithDelayRemove();
void QTBUG_45640();
+ void QTBUG_49218();
void QTBUG_48870_fastModelUpdates();
void keyNavigationEnabled();
@@ -6629,6 +6630,36 @@ void tst_QQuickGridView::QTBUG_45640()
delete window;
}
+void tst_QQuickGridView::QTBUG_49218()
+{
+ QQuickView *window = createView();
+ window->setSource(testFileUrl("qtbug49218.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickItem *rootItem = qobject_cast<QQuickItem*>(window->rootObject());
+ QQuickGridView *gridview = qobject_cast<QQuickGridView *>(rootItem->childItems().first());
+ QVERIFY(gridview != 0);
+
+ auto processEventsAndForceLayout = [&gridview] () {
+ for (int pass = 0; pass < 2; ++pass) {
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
+ gridview->forceLayout();
+ }
+ };
+ QMetaObject::invokeMethod(rootItem, "scrollToTop");
+ processEventsAndForceLayout();
+ QMetaObject::invokeMethod(rootItem, "changeModel");
+ processEventsAndForceLayout();
+ QMetaObject::invokeMethod(rootItem, "changeModel");
+ processEventsAndForceLayout();
+ QMetaObject::invokeMethod(rootItem, "scrollToTop");
+ processEventsAndForceLayout();
+
+ QCOMPARE(gridview->indexAt(gridview->cellWidth() - 10, gridview->cellHeight() - 10), 0);
+ delete window;
+}
+
void tst_QQuickGridView::keyNavigationEnabled()
{
QScopedPointer<QQuickView> window(createView());
diff --git a/tests/auto/quick/qquicklistview/data/addoncompleted.qml b/tests/auto/quick/qquicklistview/data/addoncompleted.qml
new file mode 100644
index 0000000000..57265cb2c0
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/addoncompleted.qml
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.9
+
+Rectangle {
+ width: 640
+ height: 480
+ color: "green"
+
+ ListModel {
+ id: listModel
+ ListElement { name: "a" }
+ ListElement { name: "b" }
+ ListElement { name: "c" }
+ ListElement { name: "d" }
+ ListElement { name: "e" }
+ ListElement { name: "f" }
+ ListElement { name: "g" }
+ ListElement { name: "h" }
+ ListElement { name: "i" }
+ ListElement { name: "j" }
+ }
+
+ ListView {
+ anchors.fill: parent
+ model: listModel
+ objectName: "view"
+
+ delegate: Rectangle {
+ height: 15
+ width: 15
+ color: "blue"
+ objectName: name
+ Component.onCompleted: {
+ if (name.length === 1 && listModel.get(index + 1).name.length === 1) {
+ for (var i = 0; i < 10; ++i)
+ listModel.insert(index + 1, {name: name + i});
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 8827ad0f3a..dc8c727cbe 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -255,6 +255,7 @@ private slots:
void QTBUG_50105();
void keyNavigationEnabled();
void QTBUG_61269_appendDuringScrollDown();
+ void QTBUG_61269_appendDuringScrollDown_data();
void QTBUG_50097_stickyHeader_positionViewAtIndex();
void QTBUG_63974_stickyHeader_positionViewAtIndex_Contain();
void itemFiltered();
@@ -263,6 +264,8 @@ private slots:
void QTBUG_34576_velocityZero();
void QTBUG_61537_modelChangesAsync();
+ void addOnCompleted();
+
private:
template <class T> void items(const QUrl &source);
template <class T> void changed(const QUrl &source);
@@ -8468,8 +8471,19 @@ void tst_QQuickListView::keyNavigationEnabled()
QCOMPARE(listView->currentIndex(), 1);
}
-void tst_QQuickListView::QTBUG_61269_appendDuringScrollDown()
+void tst_QQuickListView::QTBUG_61269_appendDuringScrollDown_data()
+{
+ QTest::addColumn<QQuickListView::SnapMode>("snapMode");
+
+ QTest::newRow("NoSnap") << QQuickListView::NoSnap;
+ QTest::newRow("SnapToItem") << QQuickListView::SnapToItem;
+ QTest::newRow("SnapOneItem") << QQuickListView::SnapOneItem;
+}
+
+void tst_QQuickListView::QTBUG_61269_appendDuringScrollDown() // AKA QTBUG-62864
{
+ QFETCH(QQuickListView::SnapMode, snapMode);
+
QScopedPointer<QQuickView> window(createView());
window->setSource(testFileUrl("appendDuringScrollDown.qml"));
window->show();
@@ -8477,6 +8491,7 @@ void tst_QQuickListView::QTBUG_61269_appendDuringScrollDown()
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QQuickListView *listView = qobject_cast<QQuickListView *>(window->rootObject());
+ listView->setSnapMode(snapMode);
QQuickItem *highlightItem = listView->highlightItem();
QVERIFY(listView);
QCOMPARE(listView->isKeyNavigationEnabled(), true);
@@ -8722,6 +8737,36 @@ void tst_QQuickListView::QTBUG_61537_modelChangesAsync()
QCOMPARE(reportedCount, actualCount);
}
+void tst_QQuickListView::addOnCompleted()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("addoncompleted.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "view");
+ QTRY_VERIFY(listview != 0);
+
+ QQuickItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ qreal y = -1;
+ for (char name = 'a'; name <= 'j'; ++name) {
+ for (int num = 9; num >= 0; --num) {
+ const QString objName = QString::fromLatin1("%1%2").arg(name).arg(num);
+ QQuickItem *item = findItem<QQuickItem>(contentItem, objName);
+ if (!item) {
+ QVERIFY(name >= 'd');
+ y = 9999999;
+ } else {
+ const qreal newY = item->y();
+ QVERIFY2(newY > y, objName.toUtf8().constData());
+ y = newY;
+ }
+ }
+ }
+}
+
QTEST_MAIN(tst_QQuickListView)
#include "tst_qquicklistview.moc"
diff --git a/tests/auto/quick/qquickshortcut/data/shortcutsRect.qml b/tests/auto/quick/qquickshortcut/data/shortcutsRect.qml
new file mode 100644
index 0000000000..9aced4e530
--- /dev/null
+++ b/tests/auto/quick/qquickshortcut/data/shortcutsRect.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+
+Rectangle {
+ width: 300
+ height: 300
+
+ property string activatedShortcut
+ property string ambiguousShortcut
+
+ property alias shortcuts: repeater.model
+
+ Repeater {
+ id: repeater
+
+ Item {
+ Shortcut {
+ sequence: modelData.sequence
+ enabled: modelData.enabled
+ autoRepeat: modelData.autoRepeat
+ context: modelData.context
+ onActivated: activatedShortcut = sequence
+ onActivatedAmbiguously: ambiguousShortcut = sequence
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshortcut/qquickshortcut.pro b/tests/auto/quick/qquickshortcut/qquickshortcut.pro
index d780d9061a..018bb91594 100644
--- a/tests/auto/quick/qquickshortcut/qquickshortcut.pro
+++ b/tests/auto/quick/qquickshortcut/qquickshortcut.pro
@@ -8,3 +8,6 @@ include (../../shared/util.pri)
TESTDATA = data/*
QT += core gui qml quick testlib
+qtHaveModule(widgets) {
+ QT += quickwidgets
+}
diff --git a/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp b/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp
index 75ccf26af9..4962690796 100644
--- a/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp
+++ b/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp
@@ -29,6 +29,11 @@
#include <QtTest/qtest.h>
#include <QtQuick/qquickwindow.h>
#include <QtQml/qqmlapplicationengine.h>
+#include <QtQuick/qquickitem.h>
+#include <QtTest/qsignalspy.h>
+#ifdef QT_QUICKWIDGETS_LIB
+#include <QtQuickWidgets/qquickwidget.h>
+#endif
#include "../../shared/util.h"
@@ -47,6 +52,10 @@ private slots:
void matcher();
void multiple_data();
void multiple();
+#ifdef QT_QUICKWIDGETS_LIB
+ void renderControlShortcuts_data();
+ void renderControlShortcuts();
+#endif
};
Q_DECLARE_METATYPE(Qt::Key)
@@ -453,6 +462,121 @@ void tst_QQuickShortcut::multiple()
QCOMPARE(window->property("activated").toBool(), activated);
}
+#ifdef QT_QUICKWIDGETS_LIB
+void tst_QQuickShortcut::renderControlShortcuts_data()
+{
+ QTest::addColumn<QVariantList>("shortcuts");
+ QTest::addColumn<Qt::Key>("key");
+ QTest::addColumn<Qt::KeyboardModifiers>("modifiers");
+ QTest::addColumn<QString>("activatedShortcut");
+ QTest::addColumn<QString>("ambiguousShortcut");
+
+ QVariantList shortcuts;
+ shortcuts << shortcutMap("M")
+ << shortcutMap("Alt+M")
+ << shortcutMap("Ctrl+M")
+ << shortcutMap("Shift+M")
+ << shortcutMap("Ctrl+Alt+M")
+ << shortcutMap("+")
+ << shortcutMap("F1")
+ << shortcutMap("Shift+F1");
+
+ QTest::newRow("M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "M" << "";
+ QTest::newRow("Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "Alt+M" << "";
+ QTest::newRow("Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "Ctrl+M" << "";
+ QTest::newRow("Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+M" << "";
+ QTest::newRow("Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "Ctrl+Alt+M" << "";
+ QTest::newRow("+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "+" << "";
+ QTest::newRow("F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "F1" << "";
+ QTest::newRow("Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+F1" << "";
+
+ // ambiguous
+ shortcuts << shortcutMap("M")
+ << shortcutMap("Alt+M")
+ << shortcutMap("Ctrl+M")
+ << shortcutMap("Shift+M")
+ << shortcutMap("Ctrl+Alt+M")
+ << shortcutMap("+")
+ << shortcutMap("F1")
+ << shortcutMap("Shift+F1");
+
+ QTest::newRow("?M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "M";
+ QTest::newRow("?Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "" << "Alt+M";
+ QTest::newRow("?Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "" << "Ctrl+M";
+ QTest::newRow("?Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << "Shift+M";
+ QTest::newRow("?Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "" << "Ctrl+Alt+M";
+ QTest::newRow("?+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "+";
+ QTest::newRow("?F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "F1";
+ QTest::newRow("?Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << "Shift+F1";
+
+ // disabled
+ shortcuts.clear();
+ shortcuts << shortcutMap("M", DisabledShortcut)
+ << shortcutMap("Alt+M", DisabledShortcut)
+ << shortcutMap("Ctrl+M", DisabledShortcut)
+ << shortcutMap("Shift+M", DisabledShortcut)
+ << shortcutMap("Ctrl+Alt+M", DisabledShortcut)
+ << shortcutMap("+", DisabledShortcut)
+ << shortcutMap("F1", DisabledShortcut)
+ << shortcutMap("Shift+F1", DisabledShortcut);
+
+ QTest::newRow("!M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "";
+ QTest::newRow("!Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "" << "";
+ QTest::newRow("!Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "" << "";
+ QTest::newRow("!Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << "";
+ QTest::newRow("!Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "" << "";
+ QTest::newRow("!+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "";
+ QTest::newRow("!F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "";
+ QTest::newRow("!Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << "";
+
+ // unambigous because others disabled
+ shortcuts << shortcutMap("M")
+ << shortcutMap("Alt+M")
+ << shortcutMap("Ctrl+M")
+ << shortcutMap("Shift+M")
+ << shortcutMap("Ctrl+Alt+M")
+ << shortcutMap("+")
+ << shortcutMap("F1")
+ << shortcutMap("Shift+F1");
+
+ QTest::newRow("/M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "M" << "";
+ QTest::newRow("/Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "Alt+M" << "";
+ QTest::newRow("/Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "Ctrl+M" << "";
+ QTest::newRow("/Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+M" << "";
+ QTest::newRow("/Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "Ctrl+Alt+M" << "";
+ QTest::newRow("/+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "+" << "";
+ QTest::newRow("/F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "F1" << "";
+ QTest::newRow("/Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+F1" << "";
+}
+
+void tst_QQuickShortcut::renderControlShortcuts()
+{
+ QFETCH(QVariantList, shortcuts);
+ QFETCH(Qt::Key, key);
+ QFETCH(Qt::KeyboardModifiers, modifiers);
+ QFETCH(QString, activatedShortcut);
+ QFETCH(QString, ambiguousShortcut);
+
+ QScopedPointer<QQuickWidget> quickWidget(new QQuickWidget);
+ quickWidget->resize(300,300);
+
+ QSignalSpy spy(qApp, &QGuiApplication::focusObjectChanged);
+
+ quickWidget->setSource(testFileUrl("shortcutsRect.qml"));
+ quickWidget->show();
+
+ spy.wait();
+
+ QVERIFY(qobject_cast<QQuickWidget*>(qApp->focusObject()) == quickWidget.data());
+
+ QQuickItem* item = quickWidget->rootObject();
+ item->setProperty("shortcuts", shortcuts);
+ QTest::keyPress(quickWidget->quickWindow(), key, modifiers, 1500);
+ QCOMPARE(item->property("activatedShortcut").toString(), activatedShortcut);
+ QCOMPARE(item->property("ambiguousShortcut").toString(), ambiguousShortcut);
+}
+#endif // QT_QUICKWIDGETS_LIB
+
QTEST_MAIN(tst_QQuickShortcut)
#include "tst_qquickshortcut.moc"
diff --git a/tests/auto/quick/touchmouse/BLACKLIST b/tests/auto/quick/touchmouse/BLACKLIST
index ac0352d10b..e0d4bff131 100644
--- a/tests/auto/quick/touchmouse/BLACKLIST
+++ b/tests/auto/quick/touchmouse/BLACKLIST
@@ -1,3 +1,5 @@
# QTBUG-40856 hover regression on pointerhandler branch: TODO fix before merging to dev
[hoverEnabled]
*
+[buttonOnDelayedPressFlickable]
+windows gcc developer-build
diff --git a/tests/auto/quickwidgets/qquickwidget/data/mouse.qml b/tests/auto/quickwidgets/qquickwidget/data/mouse.qml
new file mode 100644
index 0000000000..5d1c6e8443
--- /dev/null
+++ b/tests/auto/quickwidgets/qquickwidget/data/mouse.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 50
+ height: 50
+
+ property bool wasClicked: false
+ property bool wasDoubleClicked: false
+ property bool wasMoved: false
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ onClicked: wasClicked = true
+ onDoubleClicked: wasDoubleClicked = true
+ onMouseXChanged: wasMoved = true
+ }
+}
diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
index c0b2d8e5d8..978608def2 100644
--- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
+++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
@@ -66,6 +66,7 @@ private slots:
void keyEvents();
void shortcuts();
void enterLeave();
+ void mouseEventWindowPos();
};
@@ -474,6 +475,34 @@ void tst_qquickwidget::enterLeave()
QTRY_VERIFY(!rootItem->property("hasMouse").toBool());
}
+void tst_qquickwidget::mouseEventWindowPos()
+{
+ QWidget widget;
+ widget.resize(100, 100);
+ QQuickWidget *quick = new QQuickWidget(&widget);
+ quick->setSource(testFileUrl("mouse.qml"));
+ quick->move(50, 50);
+ widget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&widget, 5000));
+ QQuickItem *rootItem = quick->rootObject();
+ QVERIFY(rootItem);
+
+ QVERIFY(!rootItem->property("wasClicked").toBool());
+ QVERIFY(!rootItem->property("wasDoubleClicked").toBool());
+ QVERIFY(!rootItem->property("wasMoved").toBool());
+
+ QWindow *window = widget.windowHandle();
+ QVERIFY(window);
+
+ QTest::mouseMove(window, QPoint(60, 60));
+ QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(60, 60));
+ QTRY_VERIFY(rootItem->property("wasClicked").toBool());
+ QTest::mouseDClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(60, 60));
+ QTRY_VERIFY(rootItem->property("wasDoubleClicked").toBool());
+ QTest::mouseMove(window, QPoint(70, 70));
+ QTRY_VERIFY(rootItem->property("wasMoved").toBool());
+}
+
QTEST_MAIN(tst_qquickwidget)
#include "tst_qquickwidget.moc"
diff --git a/tests/benchmarks/qml/animation/tst_animation.cpp b/tests/benchmarks/qml/animation/tst_animation.cpp
index 27622ed013..f377c94f72 100644
--- a/tests/benchmarks/qml/animation/tst_animation.cpp
+++ b/tests/benchmarks/qml/animation/tst_animation.cpp
@@ -125,12 +125,12 @@ void tst_animation::animationelements_data()
void tst_animation::animationelements()
{
QFETCH(QString, type);
- QQmlType *t = QQmlMetaType::qmlType(type, 2, 0);
- if (!t || !t->isCreatable())
+ QQmlType t = QQmlMetaType::qmlType(type, 2, 0);
+ if (!t.isValid() || !t.isCreatable())
QSKIP("Non-creatable type");
QBENCHMARK {
- QObject *obj = t->create();
+ QObject *obj = t.create();
delete obj;
}
}
diff --git a/tests/benchmarks/qml/holistic/tst_holistic.cpp b/tests/benchmarks/qml/holistic/tst_holistic.cpp
index d7e71297f2..9186816a16 100644
--- a/tests/benchmarks/qml/holistic/tst_holistic.cpp
+++ b/tests/benchmarks/qml/holistic/tst_holistic.cpp
@@ -107,7 +107,6 @@ private slots:
void typeResolution_data();
void typeResolution();
-
};
tst_holistic::tst_holistic()
@@ -240,7 +239,6 @@ void tst_holistic::compilation_data()
void tst_holistic::compilation()
{
- QQmlEngine engine;
// This function benchmarks the cost of loading and compiling specified QML files.
// If "repetitions" is non-zero, each file from "files" will be compiled "repetitions"
// times, without clearing the engine's component cache between compilations.
@@ -250,6 +248,8 @@ void tst_holistic::compilation()
Q_ASSERT(files.size() > 0);
Q_ASSERT(repetitions > 0);
+ QQmlEngine engine;
+
QBENCHMARK {
engine.clearComponentCache();
for (int i = 0; i < repetitions; ++i) {
@@ -262,7 +262,6 @@ void tst_holistic::compilation()
void tst_holistic::instantiation()
{
- QQmlEngine engine;
// This function benchmarks the cost of instantiating components compiled from specified QML files.
// If "repetitions" is non-zero, each component compiled from "files" will be instantiated "repetitions"
// times, without clearing the component's instantiation cache between instantiations.
@@ -272,6 +271,8 @@ void tst_holistic::instantiation()
Q_ASSERT(files.size() > 0);
Q_ASSERT(repetitions > 0);
+ QQmlEngine engine;
+
QList<QQmlComponent*> components;
for (int i = 0; i < files.size(); ++i) {
QQmlComponent *c = new QQmlComponent(&engine, QUrl::fromLocalFile(files.at(i)));
@@ -297,7 +298,6 @@ void tst_holistic::instantiation()
void tst_holistic::creation()
{
- QQmlEngine engine;
// This function benchmarks the cost of loading, compiling and instantiating specified QML files.
// If "repetitions" is non-zero, each file from "files" will be created "repetitions"
// times, without clearing the engine's component cache between component creation.
@@ -307,6 +307,8 @@ void tst_holistic::creation()
Q_ASSERT(files.size() > 0);
Q_ASSERT(repetitions > 0);
+ QQmlEngine engine;
+
QBENCHMARK {
engine.clearComponentCache();
for (int i = 0; i < repetitions; ++i) {
@@ -360,7 +362,6 @@ void tst_holistic::dynamicity_data()
void tst_holistic::dynamicity()
{
- QQmlEngine engine;
// This function benchmarks the cost of "continued operation" - signal invocation,
// updating bindings, etc. Note that we take two different writeValues in order
// to force updates to occur, and we read to force lazy evaluation to occur.
@@ -371,6 +372,7 @@ void tst_holistic::dynamicity()
QFETCH(QVariant, writeValueTwo);
QFETCH(QString, readProperty);
+ QQmlEngine engine;
QQmlComponent c(&engine, file);
QObject *obj = c.create();
@@ -474,13 +476,13 @@ void tst_holistic::cppToJsDirect_data()
void tst_holistic::cppToJsDirect()
{
- QQmlEngine engine;
// This function benchmarks the cost of calling from CPP scope to JS scope
// (and possibly vice versa, if the invoked js method then calls to cpp).
QFETCH(QString, file);
QFETCH(QString, methodName);
+ QQmlEngine engine;
QQmlComponent c(&engine, file);
QObject *obj = c.create();
@@ -494,13 +496,13 @@ void tst_holistic::cppToJsDirect()
void tst_holistic::cppToJsIndirect()
{
- QQmlEngine engine;
// This function benchmarks the cost of binding scarce resources
// to properties of a QML component. The engine should automatically release such
// resources when they are no longer used.
// The benchmark deliberately causes change signals to be emitted (and
// modifies the scarce resources) so that the properties are updated.
+ QQmlEngine engine;
QQmlComponent c(&engine, QString(SRCDIR + QLatin1String("/data/scopeSwitching/ScarceTwo.qml")));
QObject *obj = c.create();
@@ -548,7 +550,6 @@ void tst_holistic::typeResolution_data()
void tst_holistic::typeResolution()
{
- QQmlEngine engine;
// This function benchmarks the cost of "continued operation" (signal invocation,
// updating bindings, etc) where the component has lots of nested items with
// lots of resolving required. Note that we take two different writeValues in order
@@ -565,6 +566,7 @@ void tst_holistic::typeResolution()
Q_ASSERT(propertyNameTwo.size() == propertyValueTwo.size());
Q_ASSERT(repetitions > 0);
+ QQmlEngine engine;
QQmlComponent c(&engine, file);
QObject *obj = c.create();
diff --git a/tests/manual/scenegraph_lancelot/data/text/text_emoji_hebrew.qml b/tests/manual/scenegraph_lancelot/data/text/text_emoji_hebrew.qml
new file mode 100644
index 0000000000..b67d584a12
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/text/text_emoji_hebrew.qml
@@ -0,0 +1,45 @@
+import QtQuick 2.0
+
+Item {
+ width: 320
+ height: 480
+
+ Component {
+ id: component
+ Column {
+ property variant listModel: model
+ Repeater {
+ model: [Text.NativeRendering, Text.QtRendering]
+ Rectangle {
+ width: text.implicitWidth
+ height: text.implicitHeight
+ color: listModel.backGroundColor ? listModel.backGroundColor : "white"
+
+ Text {
+ id: text
+ font.pixelSize: 32
+ renderType: modelData
+ text: "ื๐Ÿ˜ƒื๐Ÿ˜‡ื๐Ÿ˜ื๐Ÿ˜œื๐Ÿ˜ธ!"
+
+ color: listModel.color ? listModel.color : "black"
+ opacity: listModel.opacity ? listModel.opacity : 1.0
+ }
+ }
+ }
+ }
+ }
+
+ Column {
+ anchors.centerIn: parent
+ Repeater {
+ model: ListModel {
+ ListElement { color: "black" }
+ ListElement { color: "blue" }
+ ListElement { color: "#990000ff" }
+ ListElement { opacity: 0.5 }
+ ListElement { backGroundColor: "green" }
+ }
+ delegate: component
+ }
+ }
+}
diff --git a/tests/manual/scenegraph_lancelot/data/text/text_emoji_zwj.qml b/tests/manual/scenegraph_lancelot/data/text/text_emoji_zwj.qml
new file mode 100644
index 0000000000..4691ff7efd
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/text/text_emoji_zwj.qml
@@ -0,0 +1,45 @@
+import QtQuick 2.0
+
+Item {
+ width: 320
+ height: 480
+
+ Component {
+ id: component
+ Column {
+ property variant listModel: model
+ Repeater {
+ model: [Text.NativeRendering, Text.QtRendering]
+ Rectangle {
+ width: text.implicitWidth
+ height: text.implicitHeight
+ color: listModel.backGroundColor ? listModel.backGroundColor : "white"
+
+ Text {
+ id: text
+ font.pixelSize: 32
+ renderType: modelData
+ text: "๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ"
+
+ color: listModel.color ? listModel.color : "black"
+ opacity: listModel.opacity ? listModel.opacity : 1.0
+ }
+ }
+ }
+ }
+ }
+
+ Column {
+ anchors.centerIn: parent
+ Repeater {
+ model: ListModel {
+ ListElement { color: "black" }
+ ListElement { color: "blue" }
+ ListElement { color: "#990000ff" }
+ ListElement { opacity: 0.5 }
+ ListElement { backGroundColor: "green" }
+ }
+ delegate: component
+ }
+ }
+}
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index 054a08b084..31215daf08 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -44,6 +44,23 @@ int filterResourceFile(const QString &input, const QString &output);
bool generateLoader(const QStringList &compiledFiles, const QString &output, const QStringList &resourceFileMappings, QString *errorString);
QString symbolNamespaceForPath(const QString &relativePath);
+QSet<QString> illegalNames;
+
+void setupIllegalNames()
+{
+ // #### this in incomplete
+ illegalNames.insert(QStringLiteral("Math"));
+ illegalNames.insert(QStringLiteral("Array"));
+ illegalNames.insert(QStringLiteral("String"));
+ illegalNames.insert(QStringLiteral("Function"));
+ illegalNames.insert(QStringLiteral("Boolean"));
+ illegalNames.insert(QStringLiteral("Number"));
+ illegalNames.insert(QStringLiteral("Date"));
+ illegalNames.insert(QStringLiteral("RegExp"));
+ illegalNames.insert(QStringLiteral("Error"));
+ illegalNames.insert(QStringLiteral("Object"));
+}
+
struct Error
{
QString message;
@@ -163,7 +180,6 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti
}
{
- QSet<QString> illegalNames; // ####
QmlIR::IRBuilder irBuilder(illegalNames);
if (!irBuilder.generateFromQml(sourceCode, inputFileName, &irDocument)) {
for (const QQmlJS::DiagnosticMessage &parseError: qAsConst(irBuilder.errors)) {
@@ -181,7 +197,7 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti
QmlIR::JSCodeGen v4CodeGen(irDocument.code,
&irDocument.jsGenerator, &irDocument.jsModule,
&irDocument.jsParserEngine, irDocument.program,
- /*import cache*/0, &irDocument.jsGenerator.stringTable);
+ /*import cache*/0, &irDocument.jsGenerator.stringTable, illegalNames);
v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode
for (QmlIR::Object *object: qAsConst(irDocument.objects)) {
if (object->functionsAndExpressions->count == 0)
@@ -283,9 +299,10 @@ static bool compileJSFile(const QString &inputFileName, const QString &inputFile
QmlIR::JSCodeGen v4CodeGen(irDocument.code, &irDocument.jsGenerator,
&irDocument.jsModule, &irDocument.jsParserEngine,
irDocument.program, /*import cache*/0,
- &irDocument.jsGenerator.stringTable);
+ &irDocument.jsGenerator.stringTable, illegalNames);
v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode
- v4CodeGen.generateFromProgram(inputFileUrl, sourceCode, program, &irDocument.jsModule, QV4::Compiler::GlobalCode);
+ v4CodeGen.generateFromProgram(inputFileName, inputFileUrl, sourceCode, program,
+ &irDocument.jsModule, QV4::Compiler::GlobalCode);
QList<QQmlJS::DiagnosticMessage> jsErrors = v4CodeGen.errors();
if (!jsErrors.isEmpty()) {
for (const QQmlJS::DiagnosticMessage &e: qAsConst(jsErrors)) {
@@ -502,6 +519,8 @@ int main(int argc, char **argv)
};
}
+ setupIllegalNames();
+
if (inputFile.endsWith(QLatin1String(".qml"))) {
if (!compileQmlFile(inputFile, saveFunction, &error)) {
diff --git a/tools/qmljs/qmljs.cpp b/tools/qmljs/qmljs.cpp
index a8dd19228e..ea014f3beb 100644
--- a/tools/qmljs/qmljs.cpp
+++ b/tools/qmljs/qmljs.cpp
@@ -156,6 +156,5 @@ int main(int argc, char *argv[])
}
}
- vm.memoryManager->dumpStats();
return EXIT_SUCCESS;
}