aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKent Hansen <kent.hansen@nokia.com>2012-03-23 14:31:47 +0100
committerKent Hansen <kent.hansen@nokia.com>2012-03-23 14:31:47 +0100
commit0655209fdad022bd0f6eb20ce85522cb56506bf0 (patch)
treecdba0c1590655f5cb75a68cedff74f8a683db3a2 /src
parentc3babc03c99c6ca5fa210486e133eb456a405bab (diff)
parent3d8f103c2641f35e7681485102a1b59886db8934 (diff)
Merge master into api_changes
Conflicts: src/qml/qml/qqmlboundsignal.cpp src/qml/qml/qqmlpropertycache.cpp Change-Id: I5193a193fa301c0b518291645bf626a5fa07118f
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/javascriptcore/DateMath.cpp7
-rw-r--r--src/imports/folderlistmodel/folderlistmodel.pro2
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.cpp8
-rw-r--r--src/plugins/accessible/shared/qqmlaccessible.cpp6
-rw-r--r--src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp3
-rw-r--r--src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h2
-rw-r--r--src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro8
-rw-r--r--src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp19
-rw-r--r--src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h2
-rw-r--r--src/plugins/qmltooling/shared/qpacketprotocol.cpp (renamed from src/qml/debugger/qpacketprotocol.cpp)2
-rw-r--r--src/plugins/qmltooling/shared/qpacketprotocol.h (renamed from src/qml/debugger/qpacketprotocol_p.h)24
-rw-r--r--src/qml/debugger/debugger.pri2
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp35
-rw-r--r--src/qml/debugger/qqmldebugserverconnection_p.h2
-rw-r--r--src/qml/debugger/qqmlenginedebugservice.cpp86
-rw-r--r--src/qml/debugger/qqmlenginedebugservice_p.h6
-rw-r--r--src/qml/debugger/qqmlprofilerservice_p.h59
-rw-r--r--src/qml/debugger/qv8debugservice.cpp2
-rw-r--r--src/qml/debugger/qv8profilerservice.cpp21
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h4
-rw-r--r--src/qml/qml/ftw/qqmlpool.cpp4
-rw-r--r--src/qml/qml/qqmlaccessors_p.h4
-rw-r--r--src/qml/qml/qqmlbinding.cpp2
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp13
-rw-r--r--src/qml/qml/qqmlcompiler.cpp18
-rw-r--r--src/qml/qml/qqmlcomponent.cpp10
-rw-r--r--src/qml/qml/qqmlcontext_p.h2
-rw-r--r--src/qml/qml/qqmldirparser.cpp14
-rw-r--r--src/qml/qml/qqmldirparser_p.h3
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp2
-rw-r--r--src/qml/qml/qqmlimport.cpp28
-rw-r--r--src/qml/qml/qqmlimport_p.h2
-rw-r--r--src/qml/qml/qqmlincubator.cpp3
-rw-r--r--src/qml/qml/qqmlmetatype.cpp4
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp25
-rw-r--r--src/qml/qml/qqmlstringconverters.cpp3
-rw-r--r--src/qml/qml/qqmltypeloader.cpp41
-rw-r--r--src/qml/qml/qqmltypeloader_p.h1
-rw-r--r--src/qml/qml/qqmlvme.cpp2
-rw-r--r--src/qml/qml/qqmlwatcher.cpp5
-rw-r--r--src/qml/qml/qqmlwatcher_p.h2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp2
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp19
-rw-r--r--src/qml/qml/v4/qv4compiler.cpp10
-rw-r--r--src/qml/qml/v4/qv4instruction.cpp6
-rw-r--r--src/qml/qml/v4/qv4instruction_p.h2
-rw-r--r--src/qml/qml/v4/qv4irbuilder.cpp4
-rw-r--r--src/qml/qml/v8/qjsconverter_impl_p.h4
-rw-r--r--src/qml/qml/v8/qjsvalue.cpp2
-rw-r--r--src/qml/qml/v8/qjsvalue_impl_p.h2
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp45
-rw-r--r--src/qml/qml/v8/qv8engine.cpp7
-rw-r--r--src/qmldevtools/qmldevtools.pro2
-rw-r--r--src/qmltest/qmltest.pro2
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp4
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp4
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h8
-rw-r--r--src/quick/items/qquickcanvas.cpp166
-rw-r--r--src/quick/items/qquickcanvas.h6
-rw-r--r--src/quick/items/qquickcanvas_p.h7
-rw-r--r--src/quick/items/qquickflickable.cpp50
-rw-r--r--src/quick/items/qquickitem.cpp299
-rw-r--r--src/quick/items/qquickitem.h1
-rw-r--r--src/quick/items/qquickitem_p.h14
-rw-r--r--src/quick/items/qquickitemanimation.cpp2
-rw-r--r--src/quick/items/qquickitemview.cpp12
-rw-r--r--src/quick/items/qquickloader.cpp12
-rw-r--r--src/quick/items/qquickpathview.cpp3
-rw-r--r--src/quick/items/qquickshadereffect.cpp57
-rw-r--r--src/quick/items/qquickshadereffect_p.h3
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp14
-rw-r--r--src/quick/items/qquickshadereffectnode_p.h2
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp108
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h7
-rw-r--r--src/quick/items/qquicksprite.cpp12
-rw-r--r--src/quick/items/qquickspriteengine.cpp4
-rw-r--r--src/quick/items/qquickspriteengine_p.h2
-rw-r--r--src/quick/items/qquickspriteimage.cpp2
-rw-r--r--src/quick/items/qquicktext.cpp51
-rw-r--r--src/quick/items/qquicktextcontrol.cpp127
-rw-r--r--src/quick/items/qquicktextcontrol_p.h23
-rw-r--r--src/quick/items/qquicktextcontrol_p_p.h4
-rw-r--r--src/quick/items/qquicktextedit.cpp18
-rw-r--r--src/quick/items/qquicktextedit_p_p.h3
-rw-r--r--src/quick/items/qquicktextinput.cpp110
-rw-r--r--src/quick/items/qquicktextinput_p_p.h7
-rw-r--r--src/quick/items/qquickvisualadaptormodel.cpp3
-rw-r--r--src/quick/items/qquickwindowmanager.cpp8
-rw-r--r--src/quick/particles/qquickangledirection.cpp3
-rw-r--r--src/quick/particles/qquickcustomparticle.cpp6
-rw-r--r--src/quick/particles/qquickcustomparticle_p.h2
-rw-r--r--src/quick/particles/qquickellipseextruder.cpp5
-rw-r--r--src/quick/particles/qquickimageparticle.cpp7
-rw-r--r--src/quick/particles/qquickimageparticle_p.h2
-rw-r--r--src/quick/particles/qquickparticleemitter.cpp6
-rw-r--r--src/quick/particles/qquickparticlepainter.cpp15
-rw-r--r--src/quick/particles/qquickparticlepainter_p.h7
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.cpp4
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp191
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h108
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp140
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h5
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp107
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h161
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode.cpp76
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp28
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.h17
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h16
-rw-r--r--src/quick/scenegraph/scenegraph.pri2
-rw-r--r--src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp177
-rw-r--r--src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h142
-rw-r--r--src/quick/scenegraph/util/qsgdistancefieldutil.cpp31
-rw-r--r--src/quick/scenegraph/util/qsgdistancefieldutil_p.h10
-rw-r--r--src/quick/util/qquickpath.cpp2
-rw-r--r--src/quick/util/qquickpathinterpolator.cpp2
115 files changed, 1957 insertions, 1063 deletions
diff --git a/src/3rdparty/javascriptcore/DateMath.cpp b/src/3rdparty/javascriptcore/DateMath.cpp
index 9f66d91013..be99d2ca25 100644
--- a/src/3rdparty/javascriptcore/DateMath.cpp
+++ b/src/3rdparty/javascriptcore/DateMath.cpp
@@ -345,8 +345,15 @@ double timeClip(double t)
return NaN;
return t >= 0 ? floor(t) : ceil(t);
#else
+
+#if defined(__QNXNTO__)
+ if (!isfinite(t) || fabs(t) > maxECMAScriptTime)
+ return NaN;
+#else
if (!std::isfinite(t) || fabs(t) > maxECMAScriptTime)
return NaN;
+#endif
+
return trunc(t);
#endif
}
diff --git a/src/imports/folderlistmodel/folderlistmodel.pro b/src/imports/folderlistmodel/folderlistmodel.pro
index 592d8375c8..f30c2b2097 100644
--- a/src/imports/folderlistmodel/folderlistmodel.pro
+++ b/src/imports/folderlistmodel/folderlistmodel.pro
@@ -2,7 +2,7 @@ TARGET = qmlfolderlistmodelplugin
TARGETPATH = Qt/labs/folderlistmodel
include(../qimportbase.pri)
-QT += qml
+QT += core-private qml qml-private v8-private
SOURCES += qquickfolderlistmodel.cpp plugin.cpp \
fileinfothread.cpp
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
index 294fe184d2..0aabb7ae74 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
@@ -43,8 +43,8 @@
#include "qquickfolderlistmodel.h"
#include "fileinfothread_p.h"
#include "fileproperty_p.h"
-#include <QDebug>
#include <qqmlcontext.h>
+#include <private/qqmlengine_p.h>
QT_BEGIN_NAMESPACE
@@ -365,7 +365,8 @@ void QQuickFolderListModel::setFolder(const QUrl &folder)
if (folder == d->currentDir)
return;
- QString resolvedPath = QDir::cleanPath(folder.path());
+ QString localPath = QQmlEnginePrivate::urlToLocalFileOrQrc(folder);
+ QString resolvedPath = QDir::cleanPath(QUrl(localPath).path());
beginResetModel();
@@ -407,7 +408,8 @@ void QQuickFolderListModel::setRootFolder(const QUrl &path)
if (path.isEmpty())
return;
- QString resolvedPath = QDir::cleanPath(path.path());
+ QString localPath = QQmlEnginePrivate::urlToLocalFileOrQrc(path);
+ QString resolvedPath = QDir::cleanPath(QUrl(localPath).path());
QFileInfo info(resolvedPath);
if (!info.exists() || !info.isDir())
diff --git a/src/plugins/accessible/shared/qqmlaccessible.cpp b/src/plugins/accessible/shared/qqmlaccessible.cpp
index 70c6b90efe..54d0c06171 100644
--- a/src/plugins/accessible/shared/qqmlaccessible.cpp
+++ b/src/plugins/accessible/shared/qqmlaccessible.cpp
@@ -158,9 +158,9 @@ void QQmlAccessible::doAction(const QString &actionName)
{
// Look for and call the accessible[actionName]Action() function on the item.
// This allows for overriding the default action handling.
- const QByteArray functionName = "accessible" + actionName.toLatin1() + "Action()";
- if (object()->metaObject()->indexOfMethod(functionName) != -1) {
- QMetaObject::invokeMethod(object(), functionName, Q_ARG(QString, actionName));
+ const QByteArray functionName = "accessible" + actionName.toLatin1() + "Action";
+ if (object()->metaObject()->indexOfMethod(functionName + "()") != -1) {
+ QMetaObject::invokeMethod(object(), functionName);
return;
}
diff --git a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp
index 7d120cacb0..4dfed6c673 100644
--- a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp
+++ b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp
@@ -115,10 +115,11 @@ bool QmlOstPlugin::waitForMessage()
return d->protocol->waitForReadyRead(-1);
}
-void QmlOstPlugin::setPort(int port, bool block)
+void QmlOstPlugin::setPort(int port, bool block, const QString &hostaddress)
{
Q_UNUSED(port);
Q_UNUSED(block);
+ Q_UNUSED(hostaddress);
Q_D(QmlOstPlugin);
diff --git a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h
index 41c3a07f25..257962570c 100644
--- a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h
+++ b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h
@@ -63,7 +63,7 @@ public:
~QmlOstPlugin();
void setServer(QQmlDebugServer *server);
- void setPort(int port, bool bock);
+ void setPort(int port, bool bock, const QString &hostaddress);
bool isConnected() const;
void send(const QByteArray &message);
diff --git a/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro
index 0c5e196b18..fdd1f6e05f 100644
--- a/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro
+++ b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro
@@ -9,10 +9,14 @@ DESTDIR = $$QT.qml.plugins/qmltooling
QTDIR_build:REQUIRES += "contains(QT_CONFIG, qml)"
SOURCES += \
- qtcpserverconnection.cpp
+ qtcpserverconnection.cpp \
+ ../shared/qpacketprotocol.cpp
HEADERS += \
- qtcpserverconnection.h
+ qtcpserverconnection.h \
+ ../shared/qpacketprotocol.h
+
+INCLUDEPATH += ../shared
OTHER_FILES += qtcpserverconnection.json
diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
index 4eccd0dd55..724155a8f5 100644
--- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
+++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
@@ -40,13 +40,13 @@
****************************************************************************/
#include "qtcpserverconnection.h"
+#include "qpacketprotocol.h"
#include <QtCore/qplugin.h>
#include <QtNetwork/qtcpserver.h>
#include <QtNetwork/qtcpsocket.h>
#include <private/qqmldebugserver_p.h>
-#include <private/qpacketprotocol_p.h>
QT_BEGIN_NAMESPACE
@@ -56,6 +56,7 @@ public:
int port;
bool block;
+ QString hostaddress;
QTcpSocket *socket;
QPacketProtocol *protocol;
QTcpServer *tcpServer;
@@ -129,11 +130,12 @@ bool QTcpServerConnection::waitForMessage()
return d->protocol->waitForReadyRead(-1);
}
-void QTcpServerConnection::setPort(int port, bool block)
+void QTcpServerConnection::setPort(int port, bool block, const QString &hostaddress)
{
Q_D(QTcpServerConnection);
d->port = port;
d->block = block;
+ d->hostaddress = hostaddress;
listen();
if (block)
@@ -146,7 +148,17 @@ void QTcpServerConnection::listen()
d->tcpServer = new QTcpServer(this);
QObject::connect(d->tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
- if (d->tcpServer->listen(QHostAddress::Any, d->port))
+ QHostAddress hostaddress;
+ if (!d->hostaddress.isEmpty()) {
+ if (!hostaddress.setAddress(d->hostaddress)) {
+ hostaddress = QHostAddress::Any;
+ qDebug("QML Debugger: Incorrect host address provided. So accepting connections "
+ "from any host.");
+ }
+ } else {
+ hostaddress = QHostAddress::Any;
+ }
+ if (d->tcpServer->listen(hostaddress, d->port))
qDebug("QML Debugger: Waiting for connection on port %d...", d->port);
else
qWarning("QML Debugger: Unable to listen to port %d.", d->port);
@@ -194,4 +206,3 @@ void QTcpServerConnection::invalidPacket()
}
QT_END_NAMESPACE
-
diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h
index e81c9f7f0f..e2b32b0e4a 100644
--- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h
+++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h
@@ -62,7 +62,7 @@ public:
~QTcpServerConnection();
void setServer(QQmlDebugServer *server);
- void setPort(int port, bool bock);
+ void setPort(int port, bool bock, const QString &hostaddress);
bool isConnected() const;
void send(const QList<QByteArray> &messages);
diff --git a/src/qml/debugger/qpacketprotocol.cpp b/src/plugins/qmltooling/shared/qpacketprotocol.cpp
index 978054a238..a6a4e0e886 100644
--- a/src/qml/debugger/qpacketprotocol.cpp
+++ b/src/plugins/qmltooling/shared/qpacketprotocol.cpp
@@ -39,7 +39,7 @@
**
****************************************************************************/
-#include "qpacketprotocol_p.h"
+#include "qpacketprotocol.h"
#include <QtCore/QBuffer>
#include <QtCore/QElapsedTimer>
diff --git a/src/qml/debugger/qpacketprotocol_p.h b/src/plugins/qmltooling/shared/qpacketprotocol.h
index c6123d2836..0470c74643 100644
--- a/src/qml/debugger/qpacketprotocol_p.h
+++ b/src/plugins/qmltooling/shared/qpacketprotocol.h
@@ -42,34 +42,18 @@
#ifndef QPACKETPROTOCOL_H
#define QPACKETPROTOCOL_H
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
#include <QtCore/qobject.h>
#include <QtCore/qdatastream.h>
-#include <private/qtqmlglobal_p.h>
-
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
-
class QIODevice;
class QBuffer;
class QPacket;
class QPacketAutoSend;
class QPacketProtocolPrivate;
-class Q_QML_PRIVATE_EXPORT QPacketProtocol : public QObject
+class QPacketProtocol : public QObject
{
Q_OBJECT
public:
@@ -101,7 +85,7 @@ private:
};
-class Q_QML_PRIVATE_EXPORT QPacket : public QDataStream
+class QPacket : public QDataStream
{
public:
QPacket();
@@ -119,7 +103,7 @@ protected:
QBuffer *buf;
};
-class Q_QML_PRIVATE_EXPORT QPacketAutoSend : public QPacket
+class QPacketAutoSend : public QPacket
{
public:
virtual ~QPacketAutoSend();
@@ -132,6 +116,4 @@ private:
QT_END_NAMESPACE
-QT_END_HEADER
-
#endif
diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri
index f5abd2c196..f16e225cfd 100644
--- a/src/qml/debugger/debugger.pri
+++ b/src/qml/debugger/debugger.pri
@@ -1,5 +1,4 @@
SOURCES += \
- $$PWD/qpacketprotocol.cpp \
$$PWD/qqmldebugservice.cpp \
$$PWD/qqmlprofilerservice.cpp \
$$PWD/qqmldebugserver.cpp \
@@ -10,7 +9,6 @@ SOURCES += \
$$PWD/qdebugmessageservice.cpp
HEADERS += \
- $$PWD/qpacketprotocol_p.h \
$$PWD/qqmldebugservice_p.h \
$$PWD/qqmldebugservice_p_p.h \
$$PWD/qqmlprofilerservice_p.h \
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
index ec3f9dafc2..dcf93b400e 100644
--- a/src/qml/debugger/qqmldebugserver.cpp
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -117,9 +117,10 @@ public:
m_pluginName = pluginName;
}
- void setPort(int port, bool block) {
+ void setPort(int port, bool block, QString &hostAddress) {
m_port = port;
m_block = block;
+ m_hostAddress = hostAddress;
}
void run();
@@ -128,6 +129,7 @@ private:
QString m_pluginName;
int m_port;
bool m_block;
+ QString m_hostAddress;
};
QQmlDebugServerPrivate::QQmlDebugServerPrivate() :
@@ -214,7 +216,7 @@ void QQmlDebugServerThread::run()
= server->d_func()->loadConnectionPlugin(m_pluginName);
if (connection) {
connection->setServer(QQmlDebugServer::instance());
- connection->setPort(m_port, m_block);
+ connection->setPort(m_port, m_block, m_hostAddress);
} else {
QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
qWarning() << QString(QLatin1String("QML Debugger: Ignoring \"-qmljsdebugger=%1\". "
@@ -258,8 +260,9 @@ QQmlDebugServer *QQmlDebugServer::instance()
int port = 0;
bool block = false;
bool ok = false;
+ QString hostAddress;
- // format: qmljsdebugger=port:3768[,block] OR qmljsdebugger=ost[,block]
+ // format: qmljsdebugger=port:3768[,host:<ip address>][,block] OR qmljsdebugger=ost[,block]
if (!appD->qmljsDebugArgumentsString().isEmpty()) {
if (!QQmlEnginePrivate::qml_debugging_enabled) {
qWarning() << QString(QLatin1String(
@@ -270,24 +273,30 @@ QQmlDebugServer *QQmlDebugServer::instance()
}
QString pluginName;
- if (appD->qmljsDebugArgumentsString().indexOf(QLatin1String("port:")) == 0) {
- int separatorIndex = appD->qmljsDebugArgumentsString().indexOf(QLatin1Char(','));
- port = appD->qmljsDebugArgumentsString().mid(5, separatorIndex - 5).toInt(&ok);
- pluginName = QStringLiteral("qmldbg_tcp");
- } else if (appD->qmljsDebugArgumentsString().contains(QLatin1String("ost"))) {
- pluginName = QStringLiteral("qmldbg_ost");
- ok = true;
+ QStringList lstjsDebugArguments = appD->qmljsDebugArgumentsString()
+ .split(QLatin1Char(','));
+ foreach (const QString &strArgument, lstjsDebugArguments) {
+ if (strArgument.startsWith(QLatin1String("port:"))) {
+ port = strArgument.mid(5).toInt(&ok);
+ pluginName = QLatin1String("qmldbg_tcp");
+ } else if (strArgument.startsWith(QLatin1String("host:"))) {
+ hostAddress = strArgument.mid(5);
+ } else if (strArgument == QLatin1String("block")) {
+ block = true;
+ } else {
+ qWarning() << QString::fromLatin1("QML Debugger: Invalid argument '%1' "
+ "detected. Ignoring the same.")
+ .arg(strArgument);
+ }
}
- block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block"));
-
if (ok) {
qQmlDebugServer = new QQmlDebugServer();
QQmlDebugServerThread *thread = new QQmlDebugServerThread;
qQmlDebugServer->d_func()->thread = thread;
qQmlDebugServer->moveToThread(thread);
thread->setPluginName(pluginName);
- thread->setPort(port, block);
+ thread->setPort(port, block, hostAddress);
thread->start();
if (block) {
diff --git a/src/qml/debugger/qqmldebugserverconnection_p.h b/src/qml/debugger/qqmldebugserverconnection_p.h
index ab9e7bd73f..920e82ed47 100644
--- a/src/qml/debugger/qqmldebugserverconnection_p.h
+++ b/src/qml/debugger/qqmldebugserverconnection_p.h
@@ -69,7 +69,7 @@ public:
virtual ~QQmlDebugServerConnection() {}
virtual void setServer(QQmlDebugServer *server) = 0;
- virtual void setPort(int port, bool bock) = 0;
+ virtual void setPort(int port, bool bock, const QString &hostaddress) = 0;
virtual bool isConnected() const = 0;
virtual void send(const QList<QByteArray> &messages) = 0;
virtual void disconnect() = 0;
diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp
index 67bec3577b..7f0bf7ca33 100644
--- a/src/qml/debugger/qqmlenginedebugservice.cpp
+++ b/src/qml/debugger/qqmlenginedebugservice.cpp
@@ -67,7 +67,7 @@ QQmlEngineDebugService *QQmlEngineDebugService::instance()
}
QQmlEngineDebugService::QQmlEngineDebugService(QObject *parent)
- : QQmlDebugService(QStringLiteral("QDeclarativeEngine"), 1, parent),
+ : QQmlDebugService(QStringLiteral("QmlDebugger"), 1, parent),
m_watch(new QQmlWatcher(this)),
m_statesDelegate(0)
{
@@ -394,12 +394,10 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message)
QDataStream ds(message);
QByteArray type;
- ds >> type;
+ int queryId;
+ ds >> type >> queryId;
if (type == "LIST_ENGINES") {
- int queryId;
- ds >> queryId;
-
QByteArray reply;
QDataStream rs(&reply, QIODevice::WriteOnly);
rs << QByteArray("LIST_ENGINES_R");
@@ -416,9 +414,8 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message)
sendMessage(reply);
} else if (type == "LIST_OBJECTS") {
- int queryId;
int engineId = -1;
- ds >> queryId >> engineId;
+ ds >> engineId;
QQmlEngine *engine =
qobject_cast<QQmlEngine *>(QQmlDebugService::objectForId(engineId));
@@ -443,12 +440,11 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message)
sendMessage(reply);
} else if (type == "FETCH_OBJECT") {
- int queryId;
int objectId;
bool recurse;
bool dumpProperties = true;
- ds >> queryId >> objectId >> recurse >> dumpProperties;
+ ds >> objectId >> recurse >> dumpProperties;
QObject *object = QQmlDebugService::objectForId(objectId);
@@ -464,10 +460,9 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message)
sendMessage(reply);
} else if (type == "WATCH_OBJECT") {
- int queryId;
int objectId;
- ds >> queryId >> objectId;
+ ds >> objectId;
bool ok = m_watch->addWatch(queryId, objectId);
QByteArray reply;
@@ -476,11 +471,10 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message)
sendMessage(reply);
} else if (type == "WATCH_PROPERTY") {
- int queryId;
int objectId;
QByteArray property;
- ds >> queryId >> objectId >> property;
+ ds >> objectId >> property;
bool ok = m_watch->addWatch(queryId, objectId, property);
QByteArray reply;
@@ -489,11 +483,10 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message)
sendMessage(reply);
} else if (type == "WATCH_EXPR_OBJECT") {
- int queryId;
int debugId;
QString expr;
- ds >> queryId >> debugId >> expr;
+ ds >> debugId >> expr;
bool ok = m_watch->addWatch(queryId, debugId, expr);
QByteArray reply;
@@ -501,16 +494,17 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message)
rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok;
sendMessage(reply);
} else if (type == "NO_WATCH") {
- int queryId;
+ bool ok = m_watch->removeWatch(queryId);
- ds >> queryId;
- m_watch->removeWatch(queryId);
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("NO_WATCH_R") << queryId << ok;
+ sendMessage(reply);
} else if (type == "EVAL_EXPRESSION") {
- int queryId;
int objectId;
QString expr;
- ds >> queryId >> objectId >> expr;
+ ds >> objectId >> expr;
QObject *object = QQmlDebugService::objectForId(objectId);
QQmlContext *context = qmlContext(object);
@@ -539,26 +533,43 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message)
bool isLiteralValue;
QString filename;
int line;
- ds >> objectId >> propertyName >> expr >> isLiteralValue;
- if (!ds.atEnd()) { // backward compatibility from 2.1, 2.2
- ds >> filename >> line;
- }
- setBinding(objectId, propertyName, expr, isLiteralValue, filename, line);
+ ds >> objectId >> propertyName >> expr >> isLiteralValue >>
+ filename >> line;
+ bool ok = setBinding(objectId, propertyName, expr, isLiteralValue,
+ filename, line);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("SET_BINDING_R") << queryId << ok;
+
+ sendMessage(reply);
} else if (type == "RESET_BINDING") {
int objectId;
QString propertyName;
ds >> objectId >> propertyName;
- resetBinding(objectId, propertyName);
+ bool ok = resetBinding(objectId, propertyName);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("RESET_BINDING_R") << queryId << ok;
+
+ sendMessage(reply);
} else if (type == "SET_METHOD_BODY") {
int objectId;
QString methodName;
QString methodBody;
ds >> objectId >> methodName >> methodBody;
- setMethodBody(objectId, methodName, methodBody);
+ bool ok = setMethodBody(objectId, methodName, methodBody);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("SET_METHOD_BODY_R") << queryId << ok;
+
+ sendMessage(reply);
}
}
-void QQmlEngineDebugService::setBinding(int objectId,
+bool QQmlEngineDebugService::setBinding(int objectId,
const QString &propertyName,
const QVariant &expression,
bool isLiteralValue,
@@ -566,6 +577,7 @@ void QQmlEngineDebugService::setBinding(int objectId,
int line,
int column)
{
+ bool ok = true;
QObject *object = objectForId(objectId);
QQmlContext *context = qmlContext(object);
@@ -594,22 +606,23 @@ void QQmlEngineDebugService::setBinding(int objectId,
oldBinding->destroy();
binding->update();
} else {
+ ok = false;
qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object;
}
}
} else {
// not a valid property
- bool ok = false;
if (m_statesDelegate)
ok = m_statesDelegate->setBindingForInvalidProperty(object, propertyName, expression, isLiteralValue);
if (!ok)
qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object;
}
}
+ return ok;
}
-void QQmlEngineDebugService::resetBinding(int objectId, const QString &propertyName)
+bool QQmlEngineDebugService::resetBinding(int objectId, const QString &propertyName)
{
QObject *object = objectForId(objectId);
QQmlContext *context = qmlContext(object);
@@ -651,24 +664,25 @@ void QQmlEngineDebugService::resetBinding(int objectId, const QString &propertyN
m_statesDelegate->resetBindingForInvalidProperty(object, propertyName);
}
}
+ return true;
}
-void QQmlEngineDebugService::setMethodBody(int objectId, const QString &method, const QString &body)
+bool QQmlEngineDebugService::setMethodBody(int objectId, const QString &method, const QString &body)
{
QObject *object = objectForId(objectId);
QQmlContext *context = qmlContext(object);
if (!object || !context || !context->engine())
- return;
+ return false;
QQmlContextData *contextData = QQmlContextData::get(context);
if (!contextData)
- return;
+ return false;
QQmlPropertyData dummy;
QQmlPropertyData *prop =
QQmlPropertyCache::property(context->engine(), object, method, dummy);
if (!prop || !prop->isVMEFunction())
- return;
+ return false;
QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex);
QList<QByteArray> paramNames = metaMethod.parameterNames();
@@ -690,6 +704,7 @@ void QQmlEngineDebugService::setMethodBody(int objectId, const QString &method,
int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex);
vmeMetaObject->setVmeMethod(prop->coreIndex, QQmlExpressionPrivate::evalFunction(contextData, object, jsfunction, contextData->url.toString(), lineNumber));
+ return true;
}
void QQmlEngineDebugService::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value)
@@ -729,7 +744,8 @@ void QQmlEngineDebugService::objectCreated(QQmlEngine *engine, QObject *object)
QByteArray reply;
QDataStream rs(&reply, QIODevice::WriteOnly);
- rs << QByteArray("OBJECT_CREATED") << engineId << objectId;
+ //unique queryId -1
+ rs << QByteArray("OBJECT_CREATED") << -1 << engineId << objectId;
sendMessage(reply);
}
diff --git a/src/qml/debugger/qqmlenginedebugservice_p.h b/src/qml/debugger/qqmlenginedebugservice_p.h
index f41063d7a3..19a5776e27 100644
--- a/src/qml/debugger/qqmlenginedebugservice_p.h
+++ b/src/qml/debugger/qqmlenginedebugservice_p.h
@@ -119,9 +119,9 @@ private:
QQmlObjectData objectData(QObject *);
QQmlObjectProperty propertyData(QObject *, int);
QVariant valueContents(const QVariant &defaultValue) const;
- void setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue, QString filename = QString(), int line = -1, int column = 0);
- void resetBinding(int objectId, const QString &propertyName);
- void setMethodBody(int objectId, const QString &method, const QString &body);
+ bool setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue, QString filename = QString(), int line = -1, int column = 0);
+ bool resetBinding(int objectId, const QString &propertyName);
+ bool setMethodBody(int objectId, const QString &method, const QString &body);
QList<QQmlEngine *> m_engines;
QQmlWatcher *m_watch;
diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h
index 7a708456ba..2b4cafb615 100644
--- a/src/qml/debugger/qqmlprofilerservice_p.h
+++ b/src/qml/debugger/qqmlprofilerservice_p.h
@@ -54,12 +54,15 @@
//
#include <private/qqmldebugservice_p.h>
-#include <QtQml/qtqmlglobal.h>
+#include "qqmlexpression.h"
+
#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qmutex.h>
#include <QtCore/qvector.h>
#include <QtCore/qstringbuilder.h>
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@@ -194,47 +197,30 @@ struct QQmlBindingProfiler {
QQmlProfilerService::instance->endRange(QQmlProfilerService::Binding);
}
- void addDetail(const QString &details)
- {
- if (enabled)
- QQmlProfilerService::instance->rangeData(QQmlProfilerService::Binding,
- details);
- }
-\
bool enabled;
};
struct QQmlHandlingSignalProfiler {
- QQmlHandlingSignalProfiler()
+ QQmlHandlingSignalProfiler(const QMetaMethod &signal, QQmlExpression *expression)
{
enabled = QQmlProfilerService::instance
? QQmlProfilerService::instance->profilingEnabled() : false;
if (enabled) {
- QQmlProfilerService::instance->startRange(
- QQmlProfilerService::HandlingSignal);
+ QQmlProfilerService *service = QQmlProfilerService::instance;
+ service->startRange(QQmlProfilerService::HandlingSignal);
+ service->rangeData(QQmlProfilerService::HandlingSignal,
+ QString::fromLatin1(signal.methodSignature()) + QLatin1String(": ")
+ + expression->expression());
+ service->rangeLocation(QQmlProfilerService::HandlingSignal,
+ expression->sourceFile(), expression->lineNumber(),
+ expression->columnNumber());
}
}
- void setSignalInfo(const QString &name, const QString &expression)
- {
- if (enabled)
- QQmlProfilerService::instance->rangeData(
- QQmlProfilerService::HandlingSignal,
- name % QLatin1String(": ") % expression);
- }
-
- void setLocation(const QString &file, int line, int column)
- {
- if (enabled)
- QQmlProfilerService::instance->rangeLocation(
- QQmlProfilerService::HandlingSignal, file, line, column);
- }
-
~QQmlHandlingSignalProfiler()
{
if (enabled)
- QQmlProfilerService::instance->endRange(
- QQmlProfilerService::HandlingSignal);
+ QQmlProfilerService::instance->endRange(QQmlProfilerService::HandlingSignal);
}
bool enabled;
@@ -243,22 +229,23 @@ struct QQmlHandlingSignalProfiler {
struct QQmlObjectCreatingProfiler {
QQmlObjectCreatingProfiler()
{
- QQmlProfilerService *instance = QQmlProfilerService::instance;
- enabled = instance ?
- instance->profilingEnabled() : false;
- if (enabled)
- instance->startRange(QQmlProfilerService::Creating);
+ enabled = QQmlProfilerService::instance
+ ? QQmlProfilerService::instance->profilingEnabled() : false;
+ if (enabled) {
+ QQmlProfilerService *service = QQmlProfilerService::instance;
+ service->startRange(QQmlProfilerService::Creating);
+ }
}
void setTypeName(const QString &typeName)
{
- if (enabled)
- QQmlProfilerService::instance->rangeData(
- QQmlProfilerService::Creating, typeName);
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+ QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, typeName);
}
void setLocation(const QUrl &url, int line, int column)
{
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
if (enabled)
QQmlProfilerService::instance->rangeLocation(
QQmlProfilerService::Creating, url, line, column);
diff --git a/src/qml/debugger/qv8debugservice.cpp b/src/qml/debugger/qv8debugservice.cpp
index a6aeda31d5..7d54a59ac0 100644
--- a/src/qml/debugger/qv8debugservice.cpp
+++ b/src/qml/debugger/qv8debugservice.cpp
@@ -42,6 +42,7 @@
#include "qv8debugservice_p.h"
#include "qqmldebugservice_p_p.h"
#include <private/qjsconverter_impl_p.h>
+#include <private/qv4compiler_p.h>
#include <private/qv8engine_p.h>
#include <QtCore/QHash>
@@ -192,6 +193,7 @@ void QV8DebugService::init()
Q_D(QV8DebugService);
v8::Debug::SetMessageHandler2(DebugMessageHandler);
v8::Debug::SetDebugMessageDispatchHandler(DebugMessageDispatchHandler);
+ QV4Compiler::enableV4(false);
d->initializeMutex.unlock();
}
diff --git a/src/qml/debugger/qv8profilerservice.cpp b/src/qml/debugger/qv8profilerservice.cpp
index 6208676522..c75c258785 100644
--- a/src/qml/debugger/qv8profilerservice.cpp
+++ b/src/qml/debugger/qv8profilerservice.cpp
@@ -52,20 +52,19 @@ Q_GLOBAL_STATIC(QV8ProfilerService, v8ProfilerInstance)
class DebugServiceOutputStream : public v8::OutputStream
{
- QQmlDebugService &_service;
public:
- DebugServiceOutputStream(QQmlDebugService &service)
- : v8::OutputStream(),
- _service(service) {}
+ DebugServiceOutputStream()
+ : v8::OutputStream() {}
void EndOfStream() {}
WriteResult WriteAsciiChunk(char *rawData, int size)
{
QByteArray data;
QDataStream ds(&data, QIODevice::WriteOnly);
ds << QV8ProfilerService::V8SnapshotChunk << QByteArray(rawData, size);
- _service.sendMessage(data);
+ messages.append(data);
return kContinue;
}
+ QList<QByteArray> messages;
};
// convert to a QByteArray that can be sent to the debug client
@@ -267,16 +266,18 @@ void QV8ProfilerServicePrivate::takeSnapshot(v8::HeapSnapshot::Type snapshotType
v8::HandleScope scope;
v8::Local<v8::String> title = v8::String::New("");
- DebugServiceOutputStream outputStream(*q);
+ DebugServiceOutputStream outputStream;
const v8::HeapSnapshot *snapshot = v8::HeapProfiler::TakeSnapshot(title, snapshotType);
snapshot->Serialize(&outputStream, v8::HeapSnapshot::kJSON);
+ QList<QByteArray> messages = outputStream.messages;
//indicate completion
QByteArray data;
QDataStream ds(&data, QIODevice::WriteOnly);
ds << (int)QV8ProfilerService::V8SnapshotComplete;
+ messages.append(data);
- q->sendMessage(data);
+ q->sendMessages(messages);
}
void QV8ProfilerServicePrivate::sendMessages()
@@ -285,16 +286,16 @@ void QV8ProfilerServicePrivate::sendMessages()
QList<QByteArray> messages;
for (int i = 0; i < m_data.count(); ++i)
- messages << m_data.at(i).toByteArray();
- q->sendMessages(messages);
+ messages.append(m_data.at(i).toByteArray());
m_data.clear();
//indicate completion
QByteArray data;
QDataStream ds(&data, QIODevice::WriteOnly);
ds << (int)QV8ProfilerService::V8Complete;
+ messages.append(data);
- q->sendMessage(data);
+ q->sendMessages(messages);
}
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index f575285ff6..f058f21e98 100644
--- a/src/qml/qml/ftw/qhashedstring_p.h
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -59,6 +59,10 @@
#include <private/qflagpointer_p.h>
+#if defined(Q_OS_QNX)
+#include <stdlib.h>
+#endif
+
QT_BEGIN_NAMESPACE
// Enable this to debug hash linking assumptions.
diff --git a/src/qml/qml/ftw/qqmlpool.cpp b/src/qml/qml/ftw/qqmlpool.cpp
index 6fd11d4b1e..64df87ada5 100644
--- a/src/qml/qml/ftw/qqmlpool.cpp
+++ b/src/qml/qml/ftw/qqmlpool.cpp
@@ -41,6 +41,10 @@
#include "qqmlpool_p.h"
+#ifdef Q_OS_QNX
+#include <malloc.h>
+#endif
+
// #define POOL_DEBUG
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlaccessors_p.h b/src/qml/qml/qqmlaccessors_p.h
index a603bede9f..8e67a58511 100644
--- a/src/qml/qml/qqmlaccessors_p.h
+++ b/src/qml/qml/qqmlaccessors_p.h
@@ -47,6 +47,10 @@
#include <QtCore/qhash.h>
#include <QtCore/QReadWriteLock>
+#ifdef Q_OS_QNX
+#include <stdint.h>
+#endif
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index f43822ed0e..c4f48ef63d 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -193,8 +193,6 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
if (!updatingFlag()) {
QQmlBindingProfiler prof(m_url, m_lineNumber, m_columnNumber);
- if (prof.enabled)
- prof.addDetail(expression());
setUpdatingFlag(true);
QQmlAbstractExpression::DeleteWatcher watcher(this);
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index aa130d9493..f7d0c00a5c 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -174,13 +174,7 @@ int QQmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a)
if (QQmlDebugService::isDebuggingEnabled())
QV8DebugService::instance()->signalEmitted(QString::fromAscii(m_signal.methodSignature().constData()));
- QQmlHandlingSignalProfiler prof;
- if (prof.enabled) {
- prof.setSignalInfo(QString::fromLatin1(m_signal.methodSignature().constData()),
- m_expression->expression());
- prof.setLocation(m_expression->sourceFile(), m_expression->lineNumber(),
- m_expression->columnNumber());
- }
+ QQmlHandlingSignalProfiler prof(m_signal, m_expression);
m_isEvaluating = true;
if (!m_paramsValid) {
@@ -233,7 +227,10 @@ QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method,
prop.setWritable(false);
} else {
QByteArray propType = type;
- if (t >= int(QVariant::UserType) || t == QMetaType::UnknownType || t == QMetaType::Void) {
+ if ((QMetaType::typeFlags(t) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration) {
+ t = QVariant::Int;
+ propType = "int";
+ } else if (t == QMetaType::UnknownType) {
QByteArray scope;
QByteArray name;
int scopeIdx = propType.lastIndexOf("::");
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index c3b8152ce1..dec9911481 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -2217,7 +2217,7 @@ bool QQmlCompiler::buildValueTypeProperty(QObject *type,
//optimization for <Type>.<EnumValue> enum assignments
bool isEnumAssignment = false;
- if (prop->core.isEnum())
+ if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
if (isEnumAssignment) {
@@ -2485,7 +2485,7 @@ bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
if (v->value.isScript()) {
//optimization for <Type>.<EnumValue> enum assignments
- if (prop->core.isEnum()) {
+ if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
bool isEnumAssignment = false;
COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
if (isEnumAssignment) {
@@ -2515,8 +2515,9 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
QQmlScript::Value *v,
bool *isAssignment)
{
+ bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
*isAssignment = false;
- if (!prop->core.isEnum())
+ if (!prop->core.isEnum() && !isIntProp)
return true;
QMetaProperty mprop = obj->metaObject()->property(prop->index);
@@ -2528,6 +2529,17 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
if (!string.at(0).isUpper())
return true;
+ if (isIntProp) {
+ // Allow enum assignment to ints.
+ int enumval = evaluateEnum(string.toUtf8());
+ if (enumval != -1) {
+ v->type = Value::Literal;
+ v->value = QQmlScript::Variant((double)enumval);
+ *isAssignment = true;
+ }
+ return true;
+ }
+
QStringList parts = string.split(QLatin1Char('.'));
if (parts.count() != 2)
return true;
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 6cd5cf6cec..416178e3e1 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -829,7 +829,10 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
if (rv) {
QQmlData *ddata = QQmlData::get(rv);
Q_ASSERT(ddata);
+ //top level objects should never get JS ownership.
+ //if JS ownership is needed this needs to be explicitly undone (like in component.createObject())
ddata->indestructible = true;
+ ddata->explicitIndestructibleSet = true;
}
if (enginePriv->isDebugging && rv) {
@@ -1120,7 +1123,8 @@ void QQmlComponent::createObject(QQmlV8Function *args)
d->completeCreate();
Q_ASSERT(QQmlData::get(rv));
- QQmlData::get(rv)->setImplicitDestructible();
+ QQmlData::get(rv)->explicitIndestructibleSet = false;
+ QQmlData::get(rv)->indestructible = false;
if (!rv)
args->returnValue(v8::Null());
@@ -1255,10 +1259,6 @@ void QQmlComponentPrivate::initializeObjectWithInitialProperties(v8::Handle<v8::
v8::Handle<v8::Value> args[] = { object, valuemap };
v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
}
-
- QQmlData *ddata = QQmlData::get(toCreate);
- Q_ASSERT(ddata);
- ddata->setImplicitDestructible();
}
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index d10543bde5..97bc04b91d 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -146,7 +146,7 @@ public:
quint32 isJSContext:1;
quint32 isPragmaLibraryContext:1;
quint32 unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name
- quint32 dummy:28;
+ quint32 dummy:27;
QQmlContext *publicContext;
// VME data that is constructing this context if any
diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp
index 7b99214f04..df5f7f8ee9 100644
--- a/src/qml/qml/qqmldirparser.cpp
+++ b/src/qml/qml/qqmldirparser.cpp
@@ -295,4 +295,18 @@ QList<QQmlDirParser::TypeInfo> QQmlDirParser::typeInfos() const
}
#endif
+QDebug &operator<< (QDebug &debug, const QQmlDirParser::Component &component)
+{
+ return debug << qPrintable(QString("{%1 %2.%3}").arg(component.typeName)
+ .arg(component.majorVersion)
+ .arg(component.minorVersion));
+}
+
+QDebug &operator<< (QDebug &debug, const QQmlDirParser::Script &script)
+{
+ return debug << qPrintable(QString("{%1 %2.%3}").arg(script.nameSpace)
+ .arg(script.majorVersion)
+ .arg(script.minorVersion));
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h
index 8c681309ac..f46e1781da 100644
--- a/src/qml/qml/qqmldirparser_p.h
+++ b/src/qml/qml/qqmldirparser_p.h
@@ -55,6 +55,7 @@
#include <QtCore/QUrl>
#include <QtCore/QHash>
+#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
@@ -160,6 +161,8 @@ private:
typedef QList<QQmlDirParser::Component> QQmlDirComponents;
typedef QList<QQmlDirParser::Script> QQmlDirScripts;
+QDebug &operator<< (QDebug &, const QQmlDirParser::Component &);
+QDebug &operator<< (QDebug &, const QQmlDirParser::Script &);
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index b69fa5da7a..86d9f9588d 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -97,7 +97,7 @@ QT_BEGIN_NAMESPACE
\code
TEMPLATE = lib
CONFIG += qt plugin
- QT += declarative
+ QT += qml
DESTDIR = com/nokia/TimeExample
TARGET = qmlqtimeexampleplugin
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 0c1fb3bd93..1224efdaac 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -117,7 +117,7 @@ public:
QList<QQmlError> *errors);
QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
- bool add(const QQmlDirComponents &qmldircomponentsnetwork,
+ QString add(const QQmlDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix,
int vmaj, int vmin, QQmlScript::Import::Type importType,
QQmlImportDatabase *database, QList<QQmlError> *errors);
@@ -493,7 +493,7 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
return stableRelativePath;
}
-bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
+QString QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix, int vmaj, int vmin,
QQmlScript::Import::Type importType,
QQmlImportDatabase *database, QList<QQmlError> *errors)
@@ -540,7 +540,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
- return false;
+ return QString();
break;
}
}
@@ -564,7 +564,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
- return false;
+ return QString();
break;
}
}
@@ -586,7 +586,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
url = QUrl::fromLocalFile(absolutePath).toString();
uri = resolvedUri(dir, database);
if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
- return false;
+ return QString();
break;
}
}
@@ -604,7 +604,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg));
errors->prepend(error);
}
- return false;
+ return QString();
}
} else {
if (importType == QQmlScript::Import::File && qmldircomponents.isEmpty()) {
@@ -619,14 +619,14 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setUrl(QUrl(importUrl));
errors->prepend(error);
}
- return false; // local import dirs must exist
+ return QString(); // local import dirs must exist
}
uri = resolvedUri(dir, database);
if (uri.endsWith(Slash))
uri.chop(1);
if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) {
if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,&qmldirscripts,errors))
- return false;
+ return QString();
}
} else {
if (prefix.isEmpty()) {
@@ -642,7 +642,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setUrl(QUrl(importUrl));
errors->prepend(error);
}
- return false;
+ return QString();
}
}
}
@@ -669,7 +669,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
errors->prepend(error);
}
- return false;
+ return QString();
}
}
@@ -686,7 +686,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg(it->url));
errors->prepend(error);
- return false;
+ return QString();
}
}
@@ -716,7 +716,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
s->imports.prepend(data);
- return true;
+ return data.url;
}
bool QQmlImportsPrivate::find(const QString& type, int *vmajor, int *vminor, QQmlType** type_return,
@@ -874,9 +874,11 @@ QQmlImportDatabase::~QQmlImportDatabase()
The \a prefix may be empty, in which case the import location is considered for
unqualified types.
+ Returns the resolved URL of the import on success.
+
The base URL must already have been set with Import::setBaseUrl().
*/
-bool QQmlImports::addImport(QQmlImportDatabase *importDb,
+QString QQmlImports::addImport(QQmlImportDatabase *importDb,
const QString& uri, const QString& prefix, int vmaj, int vmin,
QQmlScript::Import::Type importType,
const QQmlDirComponents &qmldircomponentsnetwork,
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index ff19510525..422f2429a0 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -93,7 +93,7 @@ public:
QQmlType** type_return, QString* url_return,
int *version_major, int *version_minor) const;
- bool addImport(QQmlImportDatabase *,
+ QString addImport(QQmlImportDatabase *,
const QString& uri, const QString& prefix, int vmaj, int vmin,
QQmlScript::Import::Type importType,
const QQmlDirComponents &qmldircomponentsnetwork,
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index aa9777d89e..fad2ae2f28 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -293,8 +293,9 @@ void QQmlIncubatorPrivate::incubate(QQmlVME::Interrupt &i)
if (result) {
QQmlData *ddata = QQmlData::get(result);
Q_ASSERT(ddata);
+ //see QQmlComponent::beginCreate for explanation of indestructible
ddata->indestructible = true;
-
+ ddata->explicitIndestructibleSet = true;
q->setInitialState(result);
}
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 5b80f57d01..4af08c28bf 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -512,7 +512,7 @@ QObject *QQmlType::create() const
d->m_newFunc(rv);
if (rv && !d->m_metaObjects.isEmpty())
- (void *)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
+ (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
return rv;
}
@@ -525,7 +525,7 @@ void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) con
d->m_newFunc(rv);
if (rv && !d->m_metaObjects.isEmpty())
- (void *)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
+ (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
*out = rv;
*memory = ((char *)rv) + d->m_allocationSize;
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index afab665ea4..4a1eb79213 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -674,7 +674,13 @@ QStringList QQmlPropertyCache::propertyNames() const
return keys;
}
-static int EnumType(const QMetaObject *meta, const QByteArray &str)
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
+};
+
+static int EnumType(const QMetaObject *metaobj, const QByteArray &str)
{
QByteArray scope;
QByteArray name;
@@ -685,6 +691,11 @@ static int EnumType(const QMetaObject *meta, const QByteArray &str)
} else {
name = str;
}
+ const QMetaObject *meta;
+ if (scope == "Qt")
+ meta = StaticQtMetaObject::get();
+ else
+ meta = metaobj;
for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
QMetaEnum m = meta->enumerator(i);
if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
@@ -727,12 +738,14 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
for (int ii = 0; ii < argc; ++ii) {
int type = m.parameterType(ii);
- if (type == QVariant::Invalid) {
+ if ((QMetaType::typeFlags(type) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration)
+ type = QVariant::Int;
+ else if (type == QMetaType::UnknownType) {
if (argTypeNames.isEmpty())
argTypeNames = m.parameterTypes();
type = EnumType(object->metaObject(), argTypeNames.at(ii));
}
- if (type == QVariant::Invalid) {
+ if (type == QMetaType::UnknownType) {
if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
free(args);
return 0;
@@ -754,12 +767,14 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
for (int ii = 0; ii < argc; ++ii) {
int type = m.parameterType(ii);
- if (type == QVariant::Invalid) {
+ if ((QMetaType::typeFlags(type) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration)
+ type = QVariant::Int;
+ else if (type == QMetaType::UnknownType) {
if (argTypeNames.isEmpty())
argTypeNames = m.parameterTypes();
type = EnumType(object->metaObject(), argTypeNames.at(ii));
}
- if (type == QVariant::Invalid) {
+ if (type == QMetaType::UnknownType) {
if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
return 0;
}
diff --git a/src/qml/qml/qqmlstringconverters.cpp b/src/qml/qml/qqmlstringconverters.cpp
index 473097fab0..04b63ea7cd 100644
--- a/src/qml/qml/qqmlstringconverters.cpp
+++ b/src/qml/qml/qqmlstringconverters.cpp
@@ -128,6 +128,9 @@ QDateTime QQmlStringConverters::dateTimeFromString(const QString &s, bool *ok)
{
QDateTime d = QDateTime::fromString(s, Qt::ISODate);
if (ok) *ok = d.isValid();
+ // V8 never parses a date string as local time. For consistency do the same here.
+ if (d.timeSpec() == Qt::LocalTime)
+ d.setTimeSpec(Qt::UTC);
return d;
}
#endif // QT_NO_DATESTRING
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 781915e23e..abe2c0bfa4 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1558,7 +1558,6 @@ void QQmlTypeData::dataReceived(const QByteArray &data)
ref.qualifier = import.qualifier;
ref.script = blob;
m_scripts << ref;
-
}
}
@@ -1657,8 +1656,8 @@ void QQmlTypeData::resolveTypes()
import.extractVersion(&vmaj, &vmin);
QList<QQmlError> errors;
- if (!m_imports.addImport(importDatabase, import.uri, import.qualifier,
- vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) {
+ if (m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
+ import.type, qmldircomponentsnetwork, &errors).isNull()) {
QQmlError error;
if (errors.size()) {
error = errors.takeFirst();
@@ -1859,8 +1858,9 @@ void QQmlScriptBlob::dataReceived(const QByteArray &data)
import.extractVersion(&vmaj, &vmin);
QList<QQmlError> errors;
- if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
- import.type, QQmlDirComponents(), &errors)) {
+ QString importUrl = m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
+ import.type, QQmlDirComponents(), &errors);
+ if (importUrl.isNull()) {
QQmlError error = errors.takeFirst();
// description should be set by addImport().
error.setUrl(m_imports.baseUrl());
@@ -1871,6 +1871,22 @@ void QQmlScriptBlob::dataReceived(const QByteArray &data)
setError(errors);
return;
}
+
+ // Does this library contain any scripts?
+ QUrl libraryUrl(importUrl);
+ const QQmlDirParser *dirParser = typeLoader()->qmlDirParser(libraryUrl.path() + QLatin1String("qmldir"));
+ foreach (const QQmlDirParser::Script &script, dirParser->scripts()) {
+ QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
+ QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob);
+
+ ScriptReference ref;
+ ref.location = import.location.start;
+ ref.qualifier = script.nameSpace;
+ ref.nameSpace = import.qualifier;
+ ref.script = blob;
+ m_scripts << ref;
+ }
}
}
}
@@ -1902,11 +1918,20 @@ void QQmlScriptBlob::done()
m_scriptData->urlString = finalUrlString();
m_scriptData->importCache = new QQmlTypeNameCache();
- for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
- const ScriptReference &script = m_scripts.at(ii);
+ QSet<QString> ns;
+
+ for (int scriptIndex = 0; !isError() && scriptIndex < m_scripts.count(); ++scriptIndex) {
+ const ScriptReference &script = m_scripts.at(scriptIndex);
m_scriptData->scripts.append(script.script);
- m_scriptData->importCache->add(script.qualifier, ii);
+
+ if (!script.nameSpace.isNull()) {
+ if (!ns.contains(script.nameSpace)) {
+ ns.insert(script.nameSpace);
+ m_scriptData->importCache->add(script.nameSpace);
+ }
+ }
+ m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
m_imports.populateCache(m_scriptData->importCache, engine);
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index c8c2756bd5..319b2e7a10 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -390,6 +390,7 @@ public:
QQmlScript::Location location;
QString qualifier;
+ QString nameSpace;
QQmlScriptBlob *script;
};
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index 6309335e59..352684ed5e 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -829,7 +829,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
bindValues.push(binding);
binding->m_mePtr = &bindValues.top();
- Q_ASSERT(binding->propertyIndex() == property);
+ Q_ASSERT(binding->propertyIndex() == (property & 0xFF00FFFF));
Q_ASSERT(binding->object() == target);
binding->addToObject();
diff --git a/src/qml/qml/qqmlwatcher.cpp b/src/qml/qml/qqmlwatcher.cpp
index 500185762f..4eaa3d2c2a 100644
--- a/src/qml/qml/qqmlwatcher.cpp
+++ b/src/qml/qml/qqmlwatcher.cpp
@@ -166,13 +166,14 @@ bool QQmlWatcher::addWatch(int id, quint32 objectId, const QString &expr)
return false;
}
-void QQmlWatcher::removeWatch(int id)
+bool QQmlWatcher::removeWatch(int id)
{
if (!m_proxies.contains(id))
- return;
+ return false;
QList<QPointer<QQmlWatchProxy> > proxies = m_proxies.take(id);
qDeleteAll(proxies);
+ return true;
}
void QQmlWatcher::addPropertyWatch(int id, QObject *object, quint32 debugId, const QMetaProperty &property)
diff --git a/src/qml/qml/qqmlwatcher_p.h b/src/qml/qml/qqmlwatcher_p.h
index 70dc9d468c..3ca2c83777 100644
--- a/src/qml/qml/qqmlwatcher_p.h
+++ b/src/qml/qml/qqmlwatcher_p.h
@@ -77,7 +77,7 @@ public:
bool addWatch(int id, quint32 objectId, const QByteArray &property);
bool addWatch(int id, quint32 objectId, const QString &expr);
- void removeWatch(int id);
+ bool removeWatch(int id);
Q_SIGNALS:
void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value);
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index df1712976c..56743eb915 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1384,7 +1384,7 @@ void QQmlXMLHttpRequest::readEncoding()
if (header.first == "content-type") {
int separatorIdx = header.second.indexOf(';');
if (separatorIdx == -1) {
- m_mime == header.second;
+ m_mime = header.second;
} else {
m_mime = header.second.mid(0, separatorIdx);
int charsetIdx = header.second.indexOf("charset=");
diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp
index 38a3acafa2..0cd6ffd082 100644
--- a/src/qml/qml/v4/qv4bindings.cpp
+++ b/src/qml/qml/v4/qv4bindings.cpp
@@ -1153,6 +1153,25 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertColorToString, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertObjectToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined())
+ output.setUndefined();
+ else
+ output.setbool(src.getQObject() != 0);
+ }
+ QML_V4_END_INSTR(ConvertObjectToBool, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertNullToObject, unaryop)
+ {
+ Register &output = registers[instr->unaryop.output];
+ output.setQObject(0);
+ }
+ QML_V4_END_INSTR(ConvertNullToObject, unaryop)
+
QML_V4_BEGIN_INSTR(ResolveUrl, unaryop)
{
const Register &src = registers[instr->unaryop.src];
diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp
index 09b0f3861b..c9495e8987 100644
--- a/src/qml/qml/v4/qv4compiler.cpp
+++ b/src/qml/qml/v4/qv4compiler.cpp
@@ -54,7 +54,6 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP)
DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER)
-DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL)
DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
DEFINE_BOOL_CONFIG_OPTION(qmlBindingsTestEnv, QML_BINDINGS_TEST)
@@ -958,6 +957,7 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
case IR::StringType: opcode = V4Instr::ConvertStringToBool; break;
case IR::UrlType: opcode = V4Instr::ConvertUrlToBool; break;
case IR::ColorType: opcode = V4Instr::ConvertColorToBool; break;
+ case IR::ObjectType: opcode = V4Instr::ConvertObjectToBool; break;
default: break;
} // switch
} else if (targetTy == IR::IntType) {
@@ -1010,6 +1010,11 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
case IR::StringType: opcode = V4Instr::ConvertStringToColor; break;
default: break;
} // switch
+ } else if (targetTy == IR::ObjectType) {
+ switch (sourceTy) {
+ case IR::NullType: opcode = V4Instr::ConvertNullToObject; break;
+ default: break;
+ } // switch
}
if (opcode != V4Instr::Noop) {
V4Instr conv;
@@ -1354,9 +1359,6 @@ int QV4Compiler::compile(const Expression &expression, QQmlEnginePrivate *engine
{
if (!expression.expression.asAST()) return false;
- if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
- return -1;
-
if (qmlDisableOptimizer() || !qmlEnableV4)
return -1;
diff --git a/src/qml/qml/v4/qv4instruction.cpp b/src/qml/qml/v4/qv4instruction.cpp
index 1ed8bd245e..cb6ff40589 100644
--- a/src/qml/qml/v4/qv4instruction.cpp
+++ b/src/qml/qml/v4/qv4instruction.cpp
@@ -189,6 +189,12 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertColorToString:
INSTR_DUMP << "\t" << "ConvertColorToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
+ case V4Instr::ConvertObjectToBool:
+ INSTR_DUMP << "\t" << "ConvertObjectToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertNullToObject:
+ INSTR_DUMP << "\t" << "ConvertNullToObject" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
case V4Instr::ResolveUrl:
INSTR_DUMP << "\t" << "ResolveUrl" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h
index d6c790e46f..239cb362cc 100644
--- a/src/qml/qml/v4/qv4instruction_p.h
+++ b/src/qml/qml/v4/qv4instruction_p.h
@@ -98,6 +98,8 @@ QT_BEGIN_NAMESPACE
F(ConvertUrlToString, unaryop) \
F(ConvertColorToBool, unaryop) \
F(ConvertColorToString, unaryop) \
+ F(ConvertObjectToBool, unaryop) \
+ F(ConvertNullToObject, unaryop) \
F(ResolveUrl, unaryop) \
F(MathSinReal, unaryop) \
F(MathCosReal, unaryop) \
diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp
index 481b23eb4a..ea4d1afbbc 100644
--- a/src/qml/qml/v4/qv4irbuilder.cpp
+++ b/src/qml/qml/v4/qv4irbuilder.cpp
@@ -428,7 +428,7 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast)
if (r.isValid()) {
if (r.type) {
_expr.code = _block->ATTACH_TYPE(name, r.type, IR::Name::ScopeStorage, line, column);
- } else if (r.importNamespace) {
+ } /*else if (r.importNamespace) {
QQmlMetaType::ModuleApiInstance *moduleApi = m_expression->importCache->moduleApi(r.importNamespace);
if (moduleApi) {
if (moduleApi->qobjectCallback) {
@@ -439,7 +439,7 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast)
if (moduleApi->qobjectApi)
_expr.code = _block->MODULE_OBJECT(name, moduleApi->qobjectApi->metaObject(), IR::Name::MemberStorage, line, column);
}
- }
+ }*/ //### we can't create the actual QObject here, as we may be running in a thread (can be reenabled once QTBUG-24894 is handled)
// We don't support anything else
} else {
bool found = false;
diff --git a/src/qml/qml/v8/qjsconverter_impl_p.h b/src/qml/qml/v8/qjsconverter_impl_p.h
index 10b8ab5fae..c2775df7f5 100644
--- a/src/qml/qml/v8/qjsconverter_impl_p.h
+++ b/src/qml/qml/v8/qjsconverter_impl_p.h
@@ -44,6 +44,10 @@
#ifndef QJSCONVERTER_IMPL_P_H
#define QJSCONVERTER_IMPL_P_H
+#ifdef Q_OS_QNX
+#include <malloc.h>
+#endif
+
QT_BEGIN_NAMESPACE
extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str);
diff --git a/src/qml/qml/v8/qjsvalue.cpp b/src/qml/qml/v8/qjsvalue.cpp
index 4471e68a61..6ecb97d2e5 100644
--- a/src/qml/qml/v8/qjsvalue.cpp
+++ b/src/qml/qml/v8/qjsvalue.cpp
@@ -428,7 +428,7 @@ quint32 QJSValue::toUInt() const
\table
\header \li Input Type \li Result
\row \li Undefined \li An invalid QVariant.
- \row \li Null \li An invalid QVariant.
+ \row \li Null \li A QVariant containing a null pointer (QMetaType::VoidStar).
\row \li Boolean \li A QVariant containing the value of the boolean.
\row \li Number \li A QVariant containing the value of the number.
\row \li String \li A QVariant containing the value of the string.
diff --git a/src/qml/qml/v8/qjsvalue_impl_p.h b/src/qml/qml/v8/qjsvalue_impl_p.h
index fbddcfa5ba..8d22204843 100644
--- a/src/qml/qml/v8/qjsvalue_impl_p.h
+++ b/src/qml/qml/v8/qjsvalue_impl_p.h
@@ -281,7 +281,7 @@ QVariant QJSValuePrivate::toVariant() const
case CNumber:
return QVariant(u.m_number);
case CNull:
- return QVariant();
+ return QVariant(QMetaType::VoidStar, 0);
case CUndefined:
return QVariant();
case JSValue:
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 0cd5d0ad6c..9c570d756b 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -1061,7 +1061,9 @@ v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args)
QObject *obj = component.beginCreate(effectiveContext);
if (obj) {
- QQmlData::get(obj, true)->setImplicitDestructible();
+ QQmlData::get(obj, true)->explicitIndestructibleSet = false;
+ QQmlData::get(obj)->indestructible = false;
+
obj->setParent(parentArg);
@@ -1084,7 +1086,7 @@ v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args)
}
/*!
-\qmlmethod object Qt::createComponent(url, mode)
+\qmlmethod object Qt::createComponent(url, mode, parent)
Returns a \l Component object created using the QML file at the specified \a url,
or \c null if an empty string was given.
@@ -1099,6 +1101,9 @@ will be \c Component.Loading while it is loading. The status will change to
\c Component.Ready if the component loads successfully, or \c Component.Error
if loading fails.
+If the optional \a parent parameter is given, it should refer to the object
+that will become the parent for the created \l Component object.
+
Call \l {Component::createObject()}{Component.createObject()} on the returned
component to create an object instance of the component.
@@ -1114,7 +1119,8 @@ use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}.
v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
{
const char *invalidArgs = "Qt.createComponent(): Invalid arguments";
- if (args.Length() < 1 || args.Length() > 2)
+ const char *invalidParent = "Qt.createComponent(): Invalid parent object";
+ if (args.Length() < 1 || args.Length() > 3)
V8THROW_ERROR(invalidArgs);
QV8Engine *v8engine = V8ENGINE();
@@ -1131,21 +1137,46 @@ v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
return v8::Null();
QQmlComponent::CompilationMode compileMode = QQmlComponent::PreferSynchronous;
- if (args.Length() == 2) {
+
+ // Default to engine parent; this will be removed in the near future (QTBUG-24841)
+ QObject *parentArg = engine;
+
+ unsigned consumedCount = 1;
+ if (args.Length() > 1) {
+ const v8::Local<v8::Value> &lastArg = args[args.Length()-1];
+
+ // The second argument could be the mode enum
if (args[1]->IsInt32()) {
int mode = args[1]->Int32Value();
if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous))
V8THROW_ERROR(invalidArgs);
compileMode = QQmlComponent::CompilationMode(mode);
+ consumedCount += 1;
} else {
- V8THROW_ERROR(invalidArgs);
+ // The second argument could be the parent only if there are exactly two args
+ if ((args.Length() != 2) || !(lastArg->IsObject() || lastArg->IsNull()))
+ V8THROW_ERROR(invalidArgs);
+ }
+
+ if (consumedCount < args.Length()) {
+ if (lastArg->IsObject()) {
+ parentArg = v8engine->toQObject(lastArg);
+ if (!parentArg)
+ V8THROW_ERROR(invalidParent);
+ } else if (lastArg->IsNull()) {
+ parentArg = 0;
+ } else {
+ V8THROW_ERROR(invalidParent);
+ }
}
}
QUrl url = context->resolvedUrl(QUrl(arg));
- QQmlComponent *c = new QQmlComponent(engine, url, compileMode, engine);
+ QQmlComponent *c = new QQmlComponent(engine, url, compileMode, parentArg);
QQmlComponentPrivate::get(c)->creationContext = effectiveContext;
- QQmlData::get(c, true)->setImplicitDestructible();
+ QQmlData::get(c, true)->explicitIndestructibleSet = false;
+ QQmlData::get(c)->indestructible = false;
+
return v8engine->newQObject(c);
}
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index f0df025541..678f9aa3ee 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -1368,7 +1368,8 @@ v8::Handle<v8::Value> QV8Engine::variantToJS(const QVariant &value)
}
// Converts a JS value to a QVariant.
-// Null, Undefined -> QVariant() (invalid)
+// Undefined -> QVariant() (invalid)
+// Null -> QVariant((void*)0)
// Boolean -> QVariant(bool)
// Number -> QVariant(double)
// String -> QVariant(QString)
@@ -1379,8 +1380,10 @@ v8::Handle<v8::Value> QV8Engine::variantToJS(const QVariant &value)
QVariant QV8Engine::variantFromJS(v8::Handle<v8::Value> value)
{
Q_ASSERT(!value.IsEmpty());
- if (value->IsNull() || value->IsUndefined())
+ if (value->IsUndefined())
return QVariant();
+ if (value->IsNull())
+ return QVariant(QMetaType::VoidStar, 0);
if (value->IsBoolean())
return value->ToBoolean()->Value();
if (value->IsInt32())
diff --git a/src/qmldevtools/qmldevtools.pro b/src/qmldevtools/qmldevtools.pro
index 97b3788dcd..4dd21c6110 100644
--- a/src/qmldevtools/qmldevtools.pro
+++ b/src/qmldevtools/qmldevtools.pro
@@ -17,4 +17,4 @@ HEADERS += qtqmldevtoolsversion.h
unix|win32-g++*:QMAKE_PKGCONFIG_REQUIRES = QtCore
-include($$QT.qml.sources/qml/parser/parser.pri)
+include(../qml/qml/parser/parser.pri)
diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro
index b1c99d2739..6df36d20cb 100644
--- a/src/qmltest/qmltest.pro
+++ b/src/qmltest/qmltest.pro
@@ -4,7 +4,7 @@ TARGET = QtQuickTest
QPRO_PWD = $$PWD
CONFIG += module
-CONFIG += dll warn_on declarative_debug
+CONFIG += dll warn_on
MODULE_PRI += ../../modules/qt_qmltest.pri
QT += testlib testlib-private qml quick gui
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index f8e5e3c57f..a605b9ce6d 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -63,6 +63,10 @@
#include <private/qv8domerrors_p.h>
#include <QtCore/qnumeric.h>
+#ifdef Q_OS_QNX
+#include <ctype.h>
+#endif
+
QT_BEGIN_NAMESPACE
/*!
\qmlclass Context2D QQuickContext2D
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 46f85417d2..27efebca0c 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -144,6 +144,10 @@ QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
// Enable accessibility for items with accessible content. This also
// enables accessibility for the ancestors of souch items.
item->d_func()->setAccessibleFlagAndListener();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessibleEvent ev(item, QAccessible::ObjectCreated);
+ QAccessible::updateAccessibility(&ev);
+#endif
}
QQuickAccessibleAttached::~QQuickAccessibleAttached()
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 129c3ef240..419f21a4b3 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -85,6 +85,10 @@ public:
if (name != m_name) {
m_name = name;
emit nameChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessibleEvent ev(parent(), QAccessible::NameChanged);
+ QAccessible::updateAccessibility(&ev);
+#endif
}
}
@@ -94,6 +98,10 @@ public:
if (m_description != description) {
m_description = description;
emit descriptionChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessibleEvent ev(parent(), QAccessible::DescriptionChanged);
+ QAccessible::updateAccessibility(&ev);
+#endif
}
}
diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp
index cd3bbbfa2a..a11f68f709 100644
--- a/src/quick/items/qquickcanvas.cpp
+++ b/src/quick/items/qquickcanvas.cpp
@@ -306,6 +306,8 @@ QQuickCanvasPrivate::QQuickCanvasPrivate()
, windowManager(0)
, clearColor(Qt::white)
, clearBeforeRendering(true)
+ , persistentGLContext(false)
+ , persistentSceneGraph(false)
, renderTarget(0)
, renderTargetId(0)
, incubationController(0)
@@ -325,6 +327,7 @@ void QQuickCanvasPrivate::init(QQuickCanvas *c)
rootItem = new QQuickRootItem;
QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem);
rootItemPrivate->canvas = q;
+ rootItemPrivate->canvasRefCount = 1;
rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
// In the absence of a focus in event on some platforms assume the window will
@@ -536,7 +539,7 @@ void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, F
q->sendEvent(oldActiveFocusItem, &event);
QQuickItem *afi = oldActiveFocusItem;
- while (afi != scope) {
+ while (afi && afi != scope) {
if (QQuickItemPrivate::get(afi)->activeFocus) {
QQuickItemPrivate::get(afi)->activeFocus = false;
changed << afi;
@@ -548,27 +551,12 @@ void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, F
if (item != rootItem && !(options & DontChangeSubFocusItem)) {
QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
- // Correct focus chain in scope
- if (oldSubFocusItem) {
- QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
- while (sfi != scope) {
- QQuickItemPrivate::get(sfi)->subFocusItem = 0;
- sfi = sfi->parentItem();
- }
- }
- {
- scopePrivate->subFocusItem = item;
- QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
- while (sfi != scope) {
- QQuickItemPrivate::get(sfi)->subFocusItem = item;
- sfi = sfi->parentItem();
- }
- }
-
if (oldSubFocusItem) {
QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
changed << oldSubFocusItem;
}
+
+ QQuickItemPrivate::get(item)->updateSubFocusItem(scope, true);
}
if (!(options & DontChangeFocusProperty)) {
@@ -647,7 +635,7 @@ void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
q->sendEvent(oldActiveFocusItem, &event);
QQuickItem *afi = oldActiveFocusItem;
- while (afi != scope) {
+ while (afi && afi != scope) {
if (QQuickItemPrivate::get(afi)->activeFocus) {
QQuickItemPrivate::get(afi)->activeFocus = false;
changed << afi;
@@ -658,20 +646,13 @@ void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
if (item != rootItem && !(options & DontChangeSubFocusItem)) {
QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
- // Correct focus chain in scope
- if (oldSubFocusItem) {
- QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
- while (sfi != scope) {
- QQuickItemPrivate::get(sfi)->subFocusItem = 0;
- sfi = sfi->parentItem();
- }
- }
- scopePrivate->subFocusItem = 0;
-
if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
changed << oldSubFocusItem;
}
+
+ QQuickItemPrivate::get(item)->updateSubFocusItem(scope, false);
+
} else if (!(options & DontChangeFocusProperty)) {
QQuickItemPrivate::get(item)->focus = false;
changed << item;
@@ -750,6 +731,55 @@ void QQuickCanvasPrivate::cleanup(QSGNode *n)
reparent the items to the root item or to an existing item in the scene.
For easily displaying a scene from a QML file, see \l{QQuickView}.
+
+
+ \section1 Scene Graph and Rendering
+
+ The QQuickCanvas uses a scene graph on top of OpenGL to render. This scene graph is disconnected
+ from the QML scene and potentially lives in another thread, depending on the platform
+ implementation. Since the rendering scene graph lives independently from the QML scene, it can
+ also be completely released without affecting the state of the QML scene.
+
+ The sceneGraphInitialized() signal is emitted on the rendering thread before the QML scene is
+ rendered to the screen for the first time. If the rendering scene graph has been released
+ the signal will be emitted again before the next frame is rendered.
+
+ Rendering is done by first copying the QML scene's state into the rendering scene graph. This is
+ done by calling QQuickItem::updatePaintNode() functions on all items that have changed. This phase
+ is run on the rendering thread with the GUI thread blocked, when a separate rendering thread
+ is being used. The scene can then be rendered.
+
+ Before the scene graph is rendered, the beforeRendering() signal is emitted. The OpenGL context
+ is bound at this point and the application is free to do its own rendering. Also
+ make sure to disable the clearing of the color buffer, using setClearBeforeRendering(). The
+ default clear color is white and can be changed with setClearColor(). After the scene has
+ been rendered, the afterRendering() signal is emitted. The application can use this to render
+ OpenGL on top of a QML application. Once the frame is fully done and has been swapped,
+ the frameSwapped() signal is emitted.
+
+ While the scene graph is being rendered on the rendering thread, the GUI will process animations
+ for the next frame. This means that as long as users are not using scene graph API
+ directly, the added complexity of a rendering thread can be completely ignored.
+
+ When a QQuickCanvas is programatically hidden with hide() or setVisible(false), it will
+ stop rendering and its scene graph and OpenGL context might be released. The
+ sceneGraphInvalidated() signal will be emitted when this happens.
+
+ \warning It is crucial that OpenGL operations and interaction with the scene graph happens
+ exclusively on the rendering thread, primarily during the updatePaintNode() phase.
+
+ \warning As signals related to rendering might be emitted from the rendering thread,
+ connections should be made using Qt::DirectConnection
+
+
+ \section1 Resource Management
+
+ QML will typically try to cache images, scene graph nodes, etc to improve performance, but in
+ some low-memory scenarios it might be required to aggressively release these resources. The
+ releaseResources() can be used to force clean up of certain resources. Calling releaseResources()
+ may result in the entire scene graph and its OpenGL context being deleted. The
+ sceneGraphInvalidated() signal will be emitted when this happens.
+
*/
QQuickCanvas::QQuickCanvas(QWindow *parent)
: QWindow(*(new QQuickCanvasPrivate), parent)
@@ -771,11 +801,6 @@ QQuickCanvas::~QQuickCanvas()
d->windowManager->canvasDestroyed(this);
- // ### should we change ~QQuickItem to handle this better?
- // manually cleanup for the root item (item destructor only handles these when an item is parented)
- QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(d->rootItem);
- rootItemPrivate->removeFromDirtyList();
-
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete d->incubationController; d->incubationController = 0;
@@ -786,6 +811,15 @@ QQuickCanvas::~QQuickCanvas()
/*!
This function tries to release redundant resources currently held by the QML scene.
+
+ Calling this function might result in the scene graph and the OpenGL context used
+ for rendering being released to release graphics memory. If this happens, the
+ sceneGraphInvalidated() signal will be called, allowing users to clean up their
+ own graphics resources. The setPersistentOpenGLContext() and setPersistentSceneGraph()
+ functions can be used to prevent this from happening, if handling the cleanup is
+ not feasible in the application, at the cost of higher memory usage.
+
+ \sa sceneGraphInvalidated(), setPersistentOpenGLContext(), setPersistentSceneGraph().
*/
void QQuickCanvas::releaseResources()
@@ -798,6 +832,69 @@ void QQuickCanvas::releaseResources()
/*!
+ Controls whether the OpenGL context can be released as a part of a call to
+ releaseResources().
+
+ The OpenGL context might still be released when the user makes an explicit
+ call to hide().
+
+ \sa setPersistentSceneGraph()
+ */
+
+void QQuickCanvas::setPersistentOpenGLContext(bool persistent)
+{
+ Q_D(QQuickCanvas);
+ d->persistentGLContext = persistent;
+}
+
+
+/*!
+ Returns whether the OpenGL context can be released as a part of a call to
+ releaseResources().
+ */
+
+bool QQuickCanvas::isPersistentOpenGLContext() const
+{
+ Q_D(const QQuickCanvas);
+ return d->persistentGLContext;
+}
+
+
+
+/*!
+ Controls whether the scene graph nodes and resources can be released as a
+ part of a call to releaseResources().
+
+ The scene graph nodes and resources might still be released when the user
+ makes an explicit call to hide().
+
+ \sa setPersistentOpenGLContext()
+ */
+
+void QQuickCanvas::setPersistentSceneGraph(bool persistent)
+{
+ Q_D(QQuickCanvas);
+ d->persistentSceneGraph = persistent;
+}
+
+
+
+/*!
+ Returns whether the scene graph nodes and resources can be released as a part
+ of a call to releaseResources().
+ */
+
+bool QQuickCanvas::isPersistentSceneGraph() const
+{
+ Q_D(const QQuickCanvas);
+ return d->persistentSceneGraph;
+}
+
+
+
+
+
+/*!
Returns the invisible root item of the scene.
A QQuickCanvas always has a single invisible root item. To add items to this canvas,
@@ -1618,6 +1715,7 @@ void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
if (p->extra.isAllocated()) {
p->extra->opacityNode = 0;
p->extra->clipNode = 0;
+ p->extra->rootNode = 0;
}
p->groupNode = 0;
diff --git a/src/quick/items/qquickcanvas.h b/src/quick/items/qquickcanvas.h
index 4ac9509896..787bb7e3c7 100644
--- a/src/quick/items/qquickcanvas.h
+++ b/src/quick/items/qquickcanvas.h
@@ -114,6 +114,12 @@ public:
void setClearColor(const QColor &color);
QColor clearColor() const;
+ void setPersistentOpenGLContext(bool persistent);
+ bool isPersistentOpenGLContext() const;
+
+ void setPersistentSceneGraph(bool persistent);
+ bool isPersistentSceneGraph() const;
+
QOpenGLContext *openglContext() const;
Q_SIGNALS:
diff --git a/src/quick/items/qquickcanvas_p.h b/src/quick/items/qquickcanvas_p.h
index 147526466e..643d694400 100644
--- a/src/quick/items/qquickcanvas_p.h
+++ b/src/quick/items/qquickcanvas_p.h
@@ -144,7 +144,7 @@ public:
void setFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions = 0);
void clearFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions = 0);
- void notifyFocusChangesRecur(QQuickItem **item, int remaining);
+ static void notifyFocusChangesRecur(QQuickItem **item, int remaining);
void updateFocusItemTransform();
@@ -184,6 +184,11 @@ public:
uint clearBeforeRendering : 1;
+ // Currently unused in the default implementation, as we're not stopping
+ // rendering when obscured as we should...
+ uint persistentGLContext : 1;
+ uint persistentSceneGraph : 1;
+
QOpenGLFramebufferObject *renderTarget;
uint renderTargetId;
QSize renderTargetSize;
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index b6d3ebd7f2..62d0e4aa41 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -887,11 +887,11 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
bool stealY = stealMouse;
bool stealX = stealMouse;
- qint64 elapsed = computeCurrentTime(event) - lastPressTime;
+ qint64 elapsedSincePress = computeCurrentTime(event) - lastPressTime;
if (q->yflick()) {
qreal dy = event->localPos().y() - pressPos.y();
- if (qAbs(dy) > qApp->styleHints()->startDragDistance() || elapsed > 200) {
+ if (qAbs(dy) > qApp->styleHints()->startDragDistance() || elapsedSincePress > 200) {
if (!vMoved)
vData.dragStartOffset = dy;
qreal newY = dy + vData.pressPos - vData.dragStartOffset;
@@ -924,7 +924,7 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
if (q->xflick()) {
qreal dx = event->localPos().x() - pressPos.x();
- if (qAbs(dx) > qApp->styleHints()->startDragDistance() || elapsed > 200) {
+ if (qAbs(dx) > qApp->styleHints()->startDragDistance() || elapsedSincePress > 200) {
if (!hMoved)
hData.dragStartOffset = dx;
qreal newX = dx + hData.pressPos - hData.dragStartOffset;
@@ -974,28 +974,26 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
q->movementStarting();
}
- if (!lastPos.isNull()) {
- qint64 currentTimestamp = computeCurrentTime(event);
- qreal elapsed = qreal(currentTimestamp - lastPosTime) / 1000.;
- if (elapsed <= 0)
- return;
- lastPosTime = currentTimestamp;
- QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event);
- if (q->yflick() && !rejectY) {
- if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
- vData.addVelocitySample(extended->velocity().y(), maxVelocity);
- } else {
- qreal dy = event->localPos().y()-lastPos.y();
- vData.addVelocitySample(dy/elapsed, maxVelocity);
- }
+ qint64 currentTimestamp = computeCurrentTime(event);
+ qreal elapsed = qreal(currentTimestamp - (lastPos.isNull() ? lastPressTime : lastPosTime)) / 1000.;
+ if (elapsed <= 0)
+ return;
+ lastPosTime = currentTimestamp;
+ QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event);
+ if (q->yflick() && !rejectY) {
+ if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
+ vData.addVelocitySample(extended->velocity().y(), maxVelocity);
+ } else {
+ qreal dy = event->localPos().y() - (lastPos.isNull() ? pressPos.y() : lastPos.y());
+ vData.addVelocitySample(dy/elapsed, maxVelocity);
}
- if (q->xflick() && !rejectX) {
- if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
- hData.addVelocitySample(extended->velocity().x(), maxVelocity);
- } else {
- qreal dx = event->localPos().x()-lastPos.x();
- hData.addVelocitySample(dx/elapsed, maxVelocity);
- }
+ }
+ if (q->xflick() && !rejectX) {
+ if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
+ hData.addVelocitySample(extended->velocity().x(), maxVelocity);
+ } else {
+ qreal dx = event->localPos().x() - (lastPos.isNull() ? pressPos.x() : lastPos.x());
+ hData.addVelocitySample(dx/elapsed, maxVelocity);
}
}
@@ -1763,6 +1761,10 @@ void QQuickFlickable::mouseUngrabEvent()
d->draggingEnding();
d->stealMouse = false;
setKeepMouseGrab(false);
+ d->fixupX();
+ d->fixupY();
+ if (!d->timeline.isActive())
+ movementEnding();
}
}
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 423fb0f40c..2a744c0559 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -1621,6 +1621,36 @@ void QQuickItemPrivate::setAccessibleFlagAndListener()
}
}
+void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
+{
+ Q_Q(QQuickItem);
+ Q_ASSERT(scope);
+
+ QQuickItemPrivate *scopePrivate = QQuickItemPrivate::get(scope);
+
+ QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
+ // Correct focus chain in scope
+ if (oldSubFocusItem) {
+ QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
+ while (sfi && sfi != scope) {
+ QQuickItemPrivate::get(sfi)->subFocusItem = 0;
+ sfi = sfi->parentItem();
+ }
+ }
+
+ if (focus) {
+ scopePrivate->subFocusItem = q;
+ QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
+ while (sfi && sfi != scope) {
+ QQuickItemPrivate::get(sfi)->subFocusItem = q;
+ sfi = sfi->parentItem();
+ }
+ } else {
+ scopePrivate->subFocusItem = 0;
+ }
+}
+
+
/*!
\class QQuickItem
\brief The QQuickItem class provides the most basic of all visual items in QML.
@@ -1794,10 +1824,13 @@ QQuickItem::~QQuickItem()
Q_D(QQuickItem);
+ if (d->canvasRefCount > 1)
+ d->canvasRefCount = 1; // Make sure canvas is set to null in next call to derefCanvas().
if (d->parentItem)
setParentItem(0);
- else if (d->canvas && d->itemNodeInstance)
- QQuickCanvasPrivate::get(d->canvas)->cleanup(d->itemNodeInstance); // cleanup root
+ else if (d->canvas)
+ d->derefCanvas();
+
// XXX todo - optimize
while (!d->childItems.isEmpty())
d->childItems.first()->setParentItem(0);
@@ -1894,19 +1927,22 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
QQuickItem *scopeItem = 0;
- if (d->canvas && hasFocus()) {
- scopeItem = oldParentItem;
- while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+ if (hasFocus())
scopeFocusedItem = this;
- } else if (d->canvas && !isFocusScope() && d->subFocusItem) {
- scopeItem = oldParentItem;
- while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+ else if (!isFocusScope() && d->subFocusItem)
scopeFocusedItem = d->subFocusItem;
- }
- if (scopeFocusedItem)
- QQuickCanvasPrivate::get(d->canvas)->clearFocusInScope(scopeItem, scopeFocusedItem,
+ if (scopeFocusedItem) {
+ scopeItem = oldParentItem;
+ while (!scopeItem->isFocusScope() && scopeItem->parentItem())
+ scopeItem = scopeItem->parentItem();
+ if (d->canvas) {
+ QQuickCanvasPrivate::get(d->canvas)->clearFocusInScope(scopeItem, scopeFocusedItem,
QQuickCanvasPrivate::DontChangeFocusProperty);
+ } else {
+ QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(scopeItem, false);
+ }
+ }
const bool wasVisible = isVisible();
op->removeChild(this);
@@ -1917,35 +1953,54 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
QQuickCanvasPrivate::get(d->canvas)->parentlessItems.remove(this);
}
- d->parentItem = parentItem;
-
- QQuickCanvas *parentCanvas = parentItem?QQuickItemPrivate::get(parentItem)->canvas:0;
- if (d->canvas != parentCanvas) {
- QQuickItemPrivate::InitializationState initState;
- initState.clear();
- d->initCanvas(&initState, parentCanvas);
+ QQuickCanvas *oldParentCanvas = oldParentItem ? QQuickItemPrivate::get(oldParentItem)->canvas : 0;
+ QQuickCanvas *parentCanvas = parentItem ? QQuickItemPrivate::get(parentItem)->canvas : 0;
+ if (oldParentCanvas == parentCanvas) {
+ // Avoid freeing and reallocating resources if the canvas stays the same.
+ d->parentItem = parentItem;
+ } else {
+ if (oldParentCanvas)
+ d->derefCanvas();
+ d->parentItem = parentItem;
+ if (parentCanvas)
+ d->refCanvas(parentCanvas);
}
d->dirty(QQuickItemPrivate::ParentChanged);
if (d->parentItem)
QQuickItemPrivate::get(d->parentItem)->addChild(this);
+ else if (d->canvas)
+ QQuickCanvasPrivate::get(d->canvas)->parentlessItems.insert(this);
d->setEffectiveVisibleRecur(d->calcEffectiveVisible());
d->setEffectiveEnableRecur(0, d->calcEffectiveEnable());
- if (scopeFocusedItem && d->parentItem && d->canvas) {
- // We need to test whether this item becomes scope focused
- QQuickItem *scopeItem = 0;
- scopeItem = d->parentItem;
- while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+ if (d->parentItem) {
+ if (!scopeFocusedItem) {
+ if (hasFocus())
+ scopeFocusedItem = this;
+ else if (!isFocusScope() && d->subFocusItem)
+ scopeFocusedItem = d->subFocusItem;
+ }
- if (scopeItem->scopedFocusItem()) {
- QQuickItemPrivate::get(scopeFocusedItem)->focus = false;
- emit scopeFocusedItem->focusChanged(false);
- } else {
- QQuickCanvasPrivate::get(d->canvas)->setFocusInScope(scopeItem, scopeFocusedItem,
- QQuickCanvasPrivate::DontChangeFocusProperty);
+ if (scopeFocusedItem) {
+ // We need to test whether this item becomes scope focused
+ QQuickItem *scopeItem = d->parentItem;
+ while (!scopeItem->isFocusScope() && scopeItem->parentItem())
+ scopeItem = scopeItem->parentItem();
+
+ if (scopeItem->scopedFocusItem()) {
+ QQuickItemPrivate::get(scopeFocusedItem)->focus = false;
+ emit scopeFocusedItem->focusChanged(false);
+ } else {
+ if (d->canvas) {
+ QQuickCanvasPrivate::get(d->canvas)->setFocusInScope(scopeItem, scopeFocusedItem,
+ QQuickCanvasPrivate::DontChangeFocusProperty);
+ } else {
+ QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(scopeItem, true);
+ }
+ }
}
}
@@ -2129,30 +2184,82 @@ QQuickItem *QQuickItemPrivate::InitializationState::getFocusScope(QQuickItem *it
return focusScope;
}
-void QQuickItemPrivate::initCanvas(InitializationState *state, QQuickCanvas *c)
+void QQuickItemPrivate::refCanvas(InitializationState *state, QQuickCanvas *c)
{
- Q_Q(QQuickItem);
+ // An item needs a canvas if it is referenced by another item which has a canvas.
+ // Typically the item is referenced by a parent, but can also be referenced by a
+ // ShaderEffect or ShaderEffectSource. 'canvasRefCount' counts how many items with
+ // a canvas is referencing this item. When the reference count goes from zero to one,
+ // or one to zero, the canvas of this item is updated and propagated to the children.
+ // As long as the reference count stays above zero, the canvas is unchanged.
+ // refCanvas() increments the reference count.
+ // derefCanvas() decrements the reference count.
- if (canvas) {
- removeFromDirtyList();
- QQuickCanvasPrivate *c = QQuickCanvasPrivate::get(canvas);
- if (polishScheduled)
- c->itemsToPolish.remove(q);
- if (c->mouseGrabberItem == q)
- c->mouseGrabberItem = 0;
- if ( hoverEnabled )
- c->hoverItems.removeAll(q);
- if (itemNodeInstance)
- c->cleanup(itemNodeInstance);
- if (!parentItem)
- c->parentlessItems.remove(q);
+ Q_Q(QQuickItem);
+ Q_ASSERT((canvas != 0) == (canvasRefCount > 0));
+ Q_ASSERT(c);
+ if (++canvasRefCount > 1) {
+ if (c != canvas)
+ qWarning("QQuickItem: Cannot use same item on different canvases at the same time.");
+ return; // Canvas already set.
}
+ Q_ASSERT(canvas == 0);
canvas = c;
- if (canvas && polishScheduled)
+ if (polishScheduled)
QQuickCanvasPrivate::get(canvas)->itemsToPolish.insert(q);
+ InitializationState _dummy;
+ InitializationState *childState = state;
+
+ if (q->isFocusScope()) {
+ _dummy.clear(q);
+ childState = &_dummy;
+ }
+
+ if (!parentItem)
+ QQuickCanvasPrivate::get(canvas)->parentlessItems.insert(q);
+
+ for (int ii = 0; ii < childItems.count(); ++ii) {
+ QQuickItem *child = childItems.at(ii);
+ QQuickItemPrivate::get(child)->refCanvas(childState, c);
+ }
+
+ dirty(Canvas);
+
+ if (extra.isAllocated() && extra->screenAttached)
+ extra->screenAttached->canvasChanged(c);
+ itemChange(QQuickItem::ItemSceneChange, c);
+}
+
+void QQuickItemPrivate::derefCanvas()
+{
+ Q_Q(QQuickItem);
+ Q_ASSERT((canvas != 0) == (canvasRefCount > 0));
+
+ if (!canvas)
+ return; // This can happen when destroying recursive shader effect sources.
+
+ if (--canvasRefCount > 0)
+ return; // There are still other references, so don't set canvas to null yet.
+
+ q->releaseResources();
+ removeFromDirtyList();
+ QQuickCanvasPrivate *c = QQuickCanvasPrivate::get(canvas);
+ if (polishScheduled)
+ c->itemsToPolish.remove(q);
+ if (c->mouseGrabberItem == q)
+ c->mouseGrabberItem = 0;
+ if ( hoverEnabled )
+ c->hoverItems.removeAll(q);
+ if (itemNodeInstance)
+ c->cleanup(itemNodeInstance);
+ if (!parentItem)
+ c->parentlessItems.remove(q);
+
+ canvas = 0;
+
itemNodeInstance = 0;
if (extra.isAllocated()) {
@@ -2165,39 +2272,19 @@ void QQuickItemPrivate::initCanvas(InitializationState *state, QQuickCanvas *c)
groupNode = 0;
paintNode = 0;
- InitializationState _dummy;
- InitializationState *childState = state;
-
- if (c && q->isFocusScope()) {
- _dummy.clear(q);
- childState = &_dummy;
- }
-
- if (!parentItem && canvas)
- QQuickCanvasPrivate::get(canvas)->parentlessItems.insert(q);
-
for (int ii = 0; ii < childItems.count(); ++ii) {
QQuickItem *child = childItems.at(ii);
- QQuickItemPrivate::get(child)->initCanvas(childState, c);
- }
-
- if (c && focus) {
- // Fixup
- if (state->getFocusScope(q)->scopedFocusItem()) {
- focus = false;
- emit q->focusChanged(false);
- } else {
- QQuickCanvasPrivate::get(canvas)->setFocusInScope(state->getFocusScope(q), q);
- }
+ QQuickItemPrivate::get(child)->derefCanvas();
}
dirty(Canvas);
if (extra.isAllocated() && extra->screenAttached)
- extra->screenAttached->canvasChanged(c);
- itemChange(QQuickItem::ItemSceneChange, c);
+ extra->screenAttached->canvasChanged(0);
+ itemChange(QQuickItem::ItemSceneChange, (QQuickCanvas *)0);
}
+
/*!
Returns a transform that maps points from canvas space into item space.
*/
@@ -2300,7 +2387,7 @@ bool QQuickItem::isComponentComplete() const
QQuickItemPrivate::QQuickItemPrivate()
: _anchors(0), _stateGroup(0),
flags(0), widthValid(false), heightValid(false), baselineOffsetValid(false), componentComplete(true),
- keepMouse(false), keepTouch(false), hoverEnabled(false), smooth(false), focus(false), activeFocus(false), notifiedFocus(false),
+ keepMouse(false), keepTouch(false), hoverEnabled(false), smooth(true), focus(false), activeFocus(false), notifiedFocus(false),
notifiedActiveFocus(false), filtersChildMouseEvents(false), explicitVisible(true),
effectiveVisible(true), explicitEnable(true), effectiveEnable(true), polishScheduled(false),
inheritedLayoutMirror(false), effectiveLayoutMirror(false), isMirrorImplicit(true),
@@ -2310,7 +2397,7 @@ QQuickItemPrivate::QQuickItemPrivate()
dirtyAttributes(0), nextDirtyItem(0), prevDirtyItem(0),
- canvas(0), parentItem(0), sortedChildItems(&childItems),
+ canvas(0), canvasRefCount(0), parentItem(0), sortedChildItems(&childItems),
subFocusItem(0),
@@ -2954,6 +3041,23 @@ QSGNode *QQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
return 0;
}
+/*!
+ This function is called when the item's scene graph resources are no longer needed.
+ It allows items to free its resources, for instance textures, that are not owned by scene graph
+ nodes. Note that scene graph nodes are managed by QQuickCanvas and should not be deleted by
+ this function. Scene graph resources are no longer needed when the parent is set to null and
+ the item is not used by any \l ShaderEffect or \l ShaderEffectSource.
+
+ This function is called from the main thread. Therefore, resources used by the scene graph
+ should not be deleted directly, but by calling \l QObject::deleteLater().
+
+ \note The item destructor still needs to free its scene graph resources if not already done.
+ */
+
+void QQuickItem::releaseResources()
+{
+}
+
QSGTransformNode *QQuickItemPrivate::createTransformNode()
{
return new QSGTransformNode;
@@ -3018,6 +3122,10 @@ void QQuickItem::inputMethodEvent(QInputMethodEvent *event)
void QQuickItem::focusInEvent(QFocusEvent *)
{
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessibleEvent ev(this, QAccessible::Focus);
+ QAccessible::updateAccessibility(&ev);
+#endif
}
void QQuickItem::focusOutEvent(QFocusEvent *)
@@ -3988,7 +4096,12 @@ bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
childVisibilityChanged |= QQuickItemPrivate::get(childItems.at(ii))->setEffectiveVisibleRecur(newEffectiveVisible);
itemChange(QQuickItem::ItemVisibleHasChanged, effectiveVisible);
-
+#ifndef QT_NO_ACCESSIBILITY
+ if (isAccessible) {
+ QAccessibleEvent ev(q, effectiveVisible ? QAccessible::ObjectShow : QAccessible::ObjectHide);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
emit q->visibleChanged();
if (childVisibilityChanged)
emit q->visibleChildrenChanged();
@@ -4217,13 +4330,15 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
/*!
\property QQuickItem::smooth
- \brief whether the item is smoothly transformed.
+ \brief whether the item is smoothed or not.
- This property is provided purely for the purpose of optimization. Turning
- smooth transforms off is faster, but looks worse; turning smooth
- transformations on is slower, but looks better.
+ Primarily used in image based elements to decide if the item should use smooth
+ sampling or not. Smooth sampling is performed using linear interpolation, while
+ non-smooth is performed using nearest neighbor.
- By default smooth transformations are off.
+ In Qt Quick 2.0, this property has minimal impact on performance.
+
+ By default is true.
*/
/*!
@@ -4650,15 +4765,33 @@ void QQuickItem::setFocus(bool focus)
if (d->focus == focus)
return;
- if (d->canvas) {
+ if (d->canvas || d->parentItem) {
// Need to find our nearest focus scope
QQuickItem *scope = parentItem();
- while (scope && !scope->isFocusScope())
+ while (scope && !scope->isFocusScope() && scope->parentItem())
scope = scope->parentItem();
- if (focus)
- QQuickCanvasPrivate::get(d->canvas)->setFocusInScope(scope, this);
- else
- QQuickCanvasPrivate::get(d->canvas)->clearFocusInScope(scope, this);
+ if (d->canvas) {
+ if (focus)
+ QQuickCanvasPrivate::get(d->canvas)->setFocusInScope(scope, this);
+ else
+ QQuickCanvasPrivate::get(d->canvas)->clearFocusInScope(scope, this);
+ } else {
+ // do the focus changes from setFocusInScope/clearFocusInScope that are
+ // unrelated to a canvas
+ QVarLengthArray<QQuickItem *, 20> changed;
+ QQuickItem *oldSubFocusItem = QQuickItemPrivate::get(scope)->subFocusItem;
+ if (oldSubFocusItem) {
+ QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
+ changed << oldSubFocusItem;
+ }
+ d->updateSubFocusItem(scope, focus);
+
+ d->focus = focus;
+ changed << this;
+ emit focusChanged(focus);
+
+ QQuickCanvasPrivate::notifyFocusChangesRecur(changed.data(), changed.count() - 1);
+ }
} else {
d->focus = focus;
emit focusChanged(focus);
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index f14d60b028..70a8ebc932 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -396,6 +396,7 @@ protected:
const QRectF &oldGeometry);
virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual void releaseResources();
virtual void updatePolish();
protected Q_SLOTS:
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 03fc66eadb..01e8b4d335 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -450,6 +450,7 @@ public:
QQuickItem**prevDirtyItem;
QQuickCanvas *canvas;
+ int canvasRefCount;
inline QSGContext *sceneGraphContext() const;
QQuickItem *parentItem;
@@ -472,9 +473,13 @@ public:
private:
QQuickItem *focusScope;
};
- void initCanvas(InitializationState *, QQuickCanvas *);
+
+ void refCanvas(QQuickCanvas *);
+ void refCanvas(InitializationState *, QQuickCanvas *);
+ void derefCanvas();
QQuickItem *subFocusItem;
+ void updateSubFocusItem(QQuickItem *scope, bool focus);
QTransform canvasToItemTransform() const;
QTransform itemToCanvasTransform() const;
@@ -856,6 +861,13 @@ QQuickItem::TransformOrigin QQuickItemPrivate::origin() const
return extra.isAllocated()?extra->origin:QQuickItem::Center;
}
+inline void QQuickItemPrivate::refCanvas(QQuickCanvas *c)
+{
+ QQuickItemPrivate::InitializationState initState;
+ initState.clear();
+ refCanvas(&initState, c);
+}
+
QSGTransformNode *QQuickItemPrivate::itemNode()
{
if (!itemNodeInstance) {
diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp
index a1c398eeb6..3e84eb6115 100644
--- a/src/quick/items/qquickitemanimation.cpp
+++ b/src/quick/items/qquickitemanimation.cpp
@@ -927,6 +927,8 @@ QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actio
void QQuickPathAnimationUpdater::setValue(qreal v)
{
+ v = qMin(qMax(v, (qreal)0.0), (qreal)1.0);;
+
if (interruptStart.isValid()) {
if (reverse)
v = 1 - v;
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 50a3216bf0..0d95500860 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -1101,9 +1101,9 @@ void QQuickItemView::trackedPositionChanged()
if (d->layoutOrientation() == Qt::Vertical)
endOffset += d->vData.endMargin;
else if (d->isContentFlowReversed())
- endOffset += d->hData.endMargin;
- else
endOffset += d->hData.startMargin;
+ else
+ endOffset += d->hData.endMargin;
trackedPos += endOffset;
trackedEndPos += endOffset;
toItemPos += endOffset;
@@ -1204,12 +1204,11 @@ qreal QQuickItemView::minXExtent() const
return QQuickFlickable::minXExtent();
if (d->hData.minExtentDirty) {
- d->minExtent = -d->startPosition();
+ d->minExtent = -d->startPosition() + d->hData.startMargin;
qreal highlightStart;
qreal highlightEnd;
qreal endPositionFirstItem = 0;
if (d->isContentFlowReversed()) {
- d->minExtent += d->hData.endMargin;
if (d->model && d->model->count())
endPositionFirstItem = d->positionAt(d->model->count()-1);
else if (d->header)
@@ -1222,7 +1221,6 @@ qreal QQuickItemView::minXExtent() const
if (d->minExtent < maxX)
d->minExtent = maxX;
} else {
- d->minExtent += d->hData.startMargin;
endPositionFirstItem = d->endPositionAt(0);
highlightStart = d->highlightRangeStart;
highlightEnd = d->highlightRangeEnd;
@@ -1279,7 +1277,7 @@ qreal QQuickItemView::maxXExtent() const
if (d->isContentFlowReversed()) {
if (d->header)
d->maxExtent -= d->headerSize();
- d->maxExtent -= d->hData.startMargin;
+ d->maxExtent -= d->hData.endMargin;
} else {
if (d->footer)
d->maxExtent -= d->footerSize();
@@ -1314,7 +1312,7 @@ qreal QQuickItemView::xOrigin() const
{
Q_D(const QQuickItemView);
if (d->isContentFlowReversed())
- return -maxXExtent() + d->size() - d->hData.startMargin;
+ return -maxXExtent() + d->size() - d->hData.endMargin;
else
return -minXExtent() + d->hData.startMargin;
}
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 59cb37c15d..f41ba44943 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -61,6 +61,8 @@ QQuickLoaderPrivate::QQuickLoaderPrivate()
QQuickLoaderPrivate::~QQuickLoaderPrivate()
{
+ delete itemContext;
+ itemContext = 0;
delete incubator;
disposeInitialPropertyValues();
}
@@ -79,12 +81,21 @@ void QQuickLoaderPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRec
void QQuickLoaderPrivate::clear()
{
+ Q_Q(QQuickLoader);
disposeInitialPropertyValues();
if (incubator)
incubator->clear();
+ delete itemContext;
+ itemContext = 0;
+
if (loadingFromSource && component) {
+ // disconnect since we deleteLater
+ QObject::disconnect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
+ q, SLOT(_q_sourceLoaded()));
+ QObject::disconnect(component, SIGNAL(progressChanged(qreal)),
+ q, SIGNAL(progressChanged()));
component->deleteLater();
component = 0;
}
@@ -545,6 +556,7 @@ void QQuickLoaderPrivate::setInitialState(QObject *obj)
QQml_setParent_noEvent(itemContext, obj);
QQml_setParent_noEvent(item, q);
item->setParentItem(q);
+ itemContext = 0;
}
if (initialPropertyValues.IsEmpty())
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 1fa0a90b28..b85a449c51 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -1422,6 +1422,9 @@ void QQuickPathView::mouseUngrabEvent()
d->stealMouse = false;
setKeepMouseGrab(false);
d->lastPosTime.invalidate();
+ d->fixOffset();
+ if (!d->tl.isActive())
+ movementEnding();
}
}
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index d7eedd42b6..e232746417 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -398,12 +398,27 @@ void QQuickShaderEffect::updateLogAndStatus(const QString &log, int status)
emit statusChanged();
}
+void QQuickShaderEffect::sourceDestroyed(QObject *object)
+{
+ for (int i = 0; i < m_sources.size(); ++i) {
+ SourceData &source = m_sources[i];
+ if (object == source.sourceObject)
+ source.sourceObject = 0;
+ }
+}
+
void QQuickShaderEffect::setSource(const QVariant &var, int index)
{
Q_ASSERT(index >= 0 && index < m_sources.size());
SourceData &source = m_sources[index];
+ if (source.sourceObject) {
+ if (canvas())
+ QQuickItemPrivate::get(source.sourceObject)->derefCanvas();
+ disconnect(source.sourceObject, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
+ }
+
source.sourceObject = 0;
if (var.isNull()) {
return;
@@ -425,16 +440,13 @@ void QQuickShaderEffect::setSource(const QVariant &var, int index)
source.sourceObject = item;
if (item) {
- QQuickItemPrivate *d = QQuickItemPrivate::get(item);
// 'item' needs a canvas to get a scene graph node. It usually gets one through its
// parent, but if the source item is "inline" rather than a reference -- i.e.
// "property variant source: Image { }" instead of "property variant source: foo" -- it
// will not get a parent. In those cases, 'item' should get the canvas from 'this'.
- if (!d->parentItem && canvas() && !d->canvas) {
- QQuickItemPrivate::InitializationState initState;
- initState.clear();
- d->initCanvas(&initState, canvas());
- }
+ if (canvas())
+ QQuickItemPrivate::get(item)->refCanvas(canvas());
+ connect(item, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
}
}
@@ -512,6 +524,11 @@ void QQuickShaderEffect::reset()
for (int i = 0; i < m_sources.size(); ++i) {
const SourceData &source = m_sources.at(i);
delete source.mapper;
+ if (source.sourceObject) {
+ if (canvas())
+ QQuickItemPrivate::get(source.sourceObject)->derefCanvas();
+ disconnect(source.sourceObject, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
+ }
}
m_sources.clear();
m_log.clear();
@@ -817,15 +834,22 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
}
for (int i = 0; i < oldTextures.size(); ++i) {
QSGTextureProvider *t = oldTextures.at(i).second;
- if (t)
+ if (t) {
disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
+ disconnect(t, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
+ }
}
for (int i = 0; i < m_sources.size(); ++i) {
const SourceData &source = m_sources.at(i);
QSGTextureProvider *t = source.sourceObject ? source.sourceObject->textureProvider() : 0;
textures.append(qMakePair(source.name, t));
- if (t)
- connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+ if (t) {
+ Q_ASSERT_X(t->thread() == QThread::currentThread(),
+ "QQuickShaderEffect::updatePaintNode",
+ "Texture provider must belong to the rendering thread");
+ connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
+ connect(t, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
+ }
}
material->setUniforms(values);
material->setTextureProviders(textures);
@@ -840,12 +864,15 @@ void QQuickShaderEffect::itemChange(ItemChange change, const ItemChangeData &val
{
if (change == QQuickItem::ItemSceneChange) {
// See comment in QQuickShaderEffect::setSource().
- for (int i = 0; i < m_sources.size(); ++i) {
- QQuickItemPrivate *d = QQuickItemPrivate::get(m_sources.at(i).sourceObject);
- if (!d->parentItem && value.canvas != d->canvas) {
- QQuickItemPrivate::InitializationState initState;
- initState.clear();
- d->initCanvas(&initState, value.canvas);
+ if (value.canvas) {
+ for (int i = 0; i < m_sources.size(); ++i) {
+ if (m_sources.at(i).sourceObject)
+ QQuickItemPrivate::get(m_sources.at(i).sourceObject)->refCanvas(value.canvas);
+ }
+ } else {
+ for (int i = 0; i < m_sources.size(); ++i) {
+ if (m_sources.at(i).sourceObject)
+ QQuickItemPrivate::get(m_sources.at(i).sourceObject)->derefCanvas();
}
}
}
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index 4475c22b28..db1e4e78c1 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -133,6 +133,7 @@ private Q_SLOTS:
void updateData();
void updateGeometry();
void updateLogAndStatus(const QString &log, int status);
+ void sourceDestroyed(QObject *object);
private:
friend class QQuickCustomMaterialShader;
@@ -156,7 +157,7 @@ private:
struct SourceData
{
QSignalMapper *mapper;
- QPointer<QQuickItem> sourceObject;
+ QQuickItem *sourceObject;
QByteArray name;
};
QVector<SourceData> m_sources;
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index ae61ad940d..c4b91844e0 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -376,6 +376,14 @@ void QQuickShaderEffectMaterial::updateTextures() const
}
}
+void QQuickShaderEffectMaterial::invalidateTextureProvider(QSGTextureProvider *provider)
+{
+ for (int i = 0; i < m_textures.size(); ++i) {
+ if (provider == m_textures.at(i).second)
+ m_textures[i].second = 0;
+ }
+}
+
QQuickShaderEffectNode::QQuickShaderEffectNode()
: m_material(this)
@@ -397,6 +405,12 @@ void QQuickShaderEffectNode::markDirtyTexture()
markDirty(DirtyMaterial);
}
+void QQuickShaderEffectNode::textureProviderDestroyed(QObject *object)
+{
+ Q_ASSERT(qobject_cast<QSGTextureProvider *>(object));
+ m_material.invalidateTextureProvider(static_cast<QSGTextureProvider *>(object));
+}
+
void QQuickShaderEffectNode::preprocess()
{
Q_ASSERT(material());
diff --git a/src/quick/items/qquickshadereffectnode_p.h b/src/quick/items/qquickshadereffectnode_p.h
index fc47f626e1..e22d2de9e2 100644
--- a/src/quick/items/qquickshadereffectnode_p.h
+++ b/src/quick/items/qquickshadereffectnode_p.h
@@ -102,6 +102,7 @@ public:
void setTextureProviders(const QVector<QPair<QByteArray, QSGTextureProvider *> > &textures);
const QVector<QPair<QByteArray, QSGTextureProvider *> > &textureProviders() const;
void updateTextures() const;
+ void invalidateTextureProvider(QSGTextureProvider *provider);
protected:
friend class QQuickCustomMaterialShader;
@@ -143,6 +144,7 @@ Q_SIGNALS:
private Q_SLOTS:
void markDirtyTexture();
+ void textureProviderDestroyed(QObject *object);
private:
QQuickShaderEffectMaterial m_material;
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 33776be712..c55b1ca7f5 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -54,6 +54,39 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY)
+namespace
+{
+ class BindableFbo : public QSGBindable
+ {
+ public:
+ BindableFbo(QOpenGLFramebufferObject *fbo, QSGDepthStencilBuffer *depthStencil);
+ virtual ~BindableFbo();
+ virtual void bind() const;
+ private:
+ QOpenGLFramebufferObject *m_fbo;
+ QSGDepthStencilBuffer *m_depthStencil;
+ };
+
+ BindableFbo::BindableFbo(QOpenGLFramebufferObject *fbo, QSGDepthStencilBuffer *depthStencil)
+ : m_fbo(fbo)
+ , m_depthStencil(depthStencil)
+ {
+ }
+
+ BindableFbo::~BindableFbo()
+ {
+ if (m_depthStencil)
+ m_depthStencil->detach();
+ }
+
+ void BindableFbo::bind() const
+ {
+ m_fbo->bind();
+ if (m_depthStencil)
+ m_depthStencil->attach();
+ }
+}
+
class QQuickShaderEffectSourceTextureProvider : public QSGTextureProvider
{
Q_OBJECT
@@ -239,6 +272,7 @@ void QQuickShaderEffectTexture::grab()
delete m_fbo;
delete m_secondaryFbo;
m_fbo = m_secondaryFbo = 0;
+ m_depthStencilBuffer.clear();
m_dirtyTexture = false;
if (m_grab)
emit scheduledUpdateCompleted();
@@ -272,13 +306,12 @@ void QQuickShaderEffectTexture::grab()
delete m_secondaryFbo;
QOpenGLFramebufferObjectFormat format;
- format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
format.setInternalTextureFormat(m_format);
format.setSamples(8);
m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
+ m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
} else {
QOpenGLFramebufferObjectFormat format;
- format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
format.setInternalTextureFormat(m_format);
format.setMipmap(m_mipmap);
if (m_recursive) {
@@ -287,6 +320,7 @@ void QQuickShaderEffectTexture::grab()
m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
updateBindOptions(true);
+ m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
} else {
delete m_fbo;
delete m_secondaryFbo;
@@ -294,6 +328,7 @@ void QQuickShaderEffectTexture::grab()
m_secondaryFbo = 0;
glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
updateBindOptions(true);
+ m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_fbo);
}
}
}
@@ -336,7 +371,7 @@ void QQuickShaderEffectTexture::grab()
m_renderer->setClearColor(Qt::transparent);
if (m_multisampling) {
- m_renderer->renderScene(QSGBindableFbo(m_secondaryFbo));
+ m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data()));
if (deleteFboLater) {
delete m_fbo;
@@ -354,7 +389,7 @@ void QQuickShaderEffectTexture::grab()
QOpenGLFramebufferObject::blitFramebuffer(m_fbo, r, m_secondaryFbo, r);
} else {
if (m_recursive) {
- m_renderer->renderScene(QSGBindableFbo(m_secondaryFbo));
+ m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data()));
if (deleteFboLater) {
delete m_fbo;
@@ -368,7 +403,7 @@ void QQuickShaderEffectTexture::grab()
}
qSwap(m_fbo, m_secondaryFbo);
} else {
- m_renderer->renderScene(QSGBindableFbo(m_fbo));
+ m_renderer->renderScene(BindableFbo(m_fbo, m_depthStencilBuffer.data()));
}
}
@@ -504,6 +539,8 @@ QQuickShaderEffectSource::~QQuickShaderEffectSource()
QQuickItemPrivate *sd = QQuickItemPrivate::get(m_sourceItem);
sd->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
sd->derefFromEffectItem(m_hideSource);
+ if (canvas())
+ sd->derefCanvas();
}
}
@@ -599,6 +636,9 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
QQuickItemPrivate *d = QQuickItemPrivate::get(m_sourceItem);
d->derefFromEffectItem(m_hideSource);
d->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
+ disconnect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
+ if (canvas())
+ d->derefCanvas();
}
m_sourceItem = item;
@@ -608,18 +648,25 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
// parent, but if the source item is "inline" rather than a reference -- i.e.
// "sourceItem: Item { }" instead of "sourceItem: foo" -- it will not get a parent.
// In those cases, 'item' should get the canvas from 'this'.
- if (!d->parentItem && canvas() && !d->canvas) {
- QQuickItemPrivate::InitializationState initState;
- initState.clear();
- d->initCanvas(&initState, canvas());
- }
+ if (canvas())
+ d->refCanvas(canvas());
d->refFromEffectItem(m_hideSource);
d->addItemChangeListener(this, QQuickItemPrivate::Geometry);
+ connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
}
update();
emit sourceItemChanged();
}
+void QQuickShaderEffectSource::sourceItemDestroyed(QObject *item)
+{
+ Q_ASSERT(item == m_sourceItem);
+ m_sourceItem = 0;
+ update();
+ emit sourceItemChanged();
+}
+
+
/*!
\qmlproperty rect ShaderEffectSource::sourceRect
@@ -841,22 +888,35 @@ static void get_wrap_mode(QQuickShaderEffectSource::WrapMode mode, QSGTexture::W
}
+void QQuickShaderEffectSource::releaseResources()
+{
+ if (m_texture) {
+ m_texture->deleteLater();
+ m_texture = 0;
+ }
+ if (m_provider) {
+ m_provider->deleteLater();
+ m_provider = 0;
+ }
+}
+
QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
if (!m_sourceItem || m_sourceItem->width() == 0 || m_sourceItem->height() == 0) {
+ if (m_texture)
+ m_texture->setItem(0);
delete oldNode;
return 0;
}
ensureTexture();
- QQuickShaderEffectTexture *tex = qobject_cast<QQuickShaderEffectTexture *>(m_texture);
- tex->setLive(m_live);
- tex->setItem(QQuickItemPrivate::get(m_sourceItem)->itemNode());
+ m_texture->setLive(m_live);
+ m_texture->setItem(QQuickItemPrivate::get(m_sourceItem)->itemNode());
QRectF sourceRect = m_sourceRect.width() == 0 || m_sourceRect.height() == 0
? QRectF(0, 0, m_sourceItem->width(), m_sourceItem->height())
: m_sourceRect;
- tex->setRect(sourceRect);
+ m_texture->setRect(sourceRect);
QSize textureSize = m_textureSize.isEmpty()
? QSize(qCeil(qAbs(sourceRect.width())), qCeil(qAbs(sourceRect.height())))
: m_textureSize;
@@ -869,13 +929,13 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
while (textureSize.height() < minTextureSize.height())
textureSize.rheight() *= 2;
- tex->setSize(textureSize);
- tex->setRecursive(m_recursive);
- tex->setFormat(GLenum(m_format));
- tex->setHasMipmaps(m_mipmap);
+ m_texture->setSize(textureSize);
+ m_texture->setRecursive(m_recursive);
+ m_texture->setFormat(GLenum(m_format));
+ m_texture->setHasMipmaps(m_mipmap);
if (m_grab)
- tex->scheduleUpdate();
+ m_texture->scheduleUpdate();
m_grab = false;
QSGTexture::Filtering filtering = QQuickItemPrivate::get(this)->smooth
@@ -924,12 +984,10 @@ void QQuickShaderEffectSource::itemChange(ItemChange change, const ItemChangeDat
{
if (change == QQuickItem::ItemSceneChange && m_sourceItem) {
// See comment in QQuickShaderEffectSource::setSourceItem().
- QQuickItemPrivate *d = QQuickItemPrivate::get(m_sourceItem);
- if (!d->parentItem && value.canvas != d->canvas) {
- QQuickItemPrivate::InitializationState initState;
- initState.clear();
- d->initCanvas(&initState, value.canvas);
- }
+ if (value.canvas)
+ QQuickItemPrivate::get(m_sourceItem)->refCanvas(value.canvas);
+ else
+ QQuickItemPrivate::get(m_sourceItem)->derefCanvas();
}
QQuickItem::itemChange(change, value);
}
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 793e89cd69..0853394339 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -136,6 +136,7 @@ private:
QSGRenderer *m_renderer;
QOpenGLFramebufferObject *m_fbo;
QOpenGLFramebufferObject *m_secondaryFbo;
+ QSharedPointer<QSGDepthStencilBuffer> m_depthStencilBuffer;
#ifdef QSG_DEBUG_FBO_OVERLAY
QSGRectangleNode *m_debugOverlay;
@@ -228,7 +229,11 @@ Q_SIGNALS:
void scheduledUpdateCompleted();
+private Q_SLOTS:
+ void sourceItemDestroyed(QObject *item);
+
protected:
+ virtual void releaseResources();
virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
virtual void itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect);
@@ -240,7 +245,7 @@ private:
QQuickShaderEffectSourceTextureProvider *m_provider;
QQuickShaderEffectTexture *m_texture;
WrapMode m_wrapMode;
- QPointer<QQuickItem> m_sourceItem;
+ QQuickItem *m_sourceItem;
QRectF m_sourceRect;
QSize m_textureSize;
Format m_format;
diff --git a/src/quick/items/qquicksprite.cpp b/src/quick/items/qquicksprite.cpp
index e0535ed77e..724bf8fef1 100644
--- a/src/quick/items/qquicksprite.cpp
+++ b/src/quick/items/qquicksprite.cpp
@@ -248,12 +248,14 @@ int QQuickSprite::variedDuration() const //Deals with precedence when multiple d
+ (m_frameDurationVariation * ((qreal)qrand()/RAND_MAX) * 2)
- m_frameDurationVariation;
return qMax(0, m_frames * mspf);
- }
- qWarning() << "Sprite::duration is changing meaning to the full animation duration.";
- qWarning() << "Use Sprite::frameDuration for the old meaning, of per frame duration.";
- qWarning() << "As an interim measure, duration/durationVariation means the same as frameDuration/frameDurationVariation, and you'll get this warning spewed out everywhere to movtivate you.";
+ } else if (duration() >= 0) {
+ qWarning() << "Sprite::duration is changing meaning to the full animation duration.";
+ qWarning() << "Use Sprite::frameDuration for the old meaning, of per frame duration.";
+ qWarning() << "As an interim measure, duration/durationVariation means the same as frameDuration/frameDurationVariation, and you'll get this warning spewed out everywhere to motivate you.";
//Note that the spammyness is due to this being the best location to detect, but also called once each animation loop
- return QQuickStochasticState::variedDuration() * m_frames;
+ return QQuickStochasticState::variedDuration() * m_frames;
+ }
+ return 1000; //When nothing set
}
void QQuickSprite::startImageLoading()
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index 1c35688c29..d4ddbc400d 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -411,9 +411,9 @@ QImage QQuickSpriteEngine::assembledImage()
int frameWidth = state->m_frameWidth;
int frameHeight = state->m_frameHeight;
if (img.height() == frameHeight && img.width() < maxSize){//Simple case
- p.drawImage(0,y,img);
+ p.drawImage(0,y,img.copy(state->m_frameX,0,state->m_frames * frameWidth, frameHeight));
+ state->m_rowStartX = 0;
state->m_rowY = y;
- state->m_rowStartX = state->m_frameX;//In case it was offset, but we took the simple route of not chopping out the other bits
y += frameHeight;
}else{//Chopping up image case
state->m_framesPerRow = image.width()/frameWidth;
diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h
index 3763509462..00cefbfbc0 100644
--- a/src/quick/items/qquickspriteengine_p.h
+++ b/src/quick/items/qquickspriteengine_p.h
@@ -70,7 +70,7 @@ class Q_AUTOTEST_EXPORT QQuickStochasticState : public QObject //Currently for i
public:
QQuickStochasticState(QObject* parent = 0)
: QObject(parent)
- , m_duration(1000)
+ , m_duration(-1)
, m_durationVariation(0)
, m_randomStart(false)
{
diff --git a/src/quick/items/qquickspriteimage.cpp b/src/quick/items/qquickspriteimage.cpp
index 6edb3ad8c3..2a151d02a8 100644
--- a/src/quick/items/qquickspriteimage.cpp
+++ b/src/quick/items/qquickspriteimage.cpp
@@ -261,7 +261,7 @@ struct SpriteVertices {
The sprite or sprites to draw. Sprites will be scaled to the size of this element.
*/
-//TODO: Implicitly size element to size of first sprite?
+//TODO: Implicitly size element to size of first sprite? or currentSprite?
QQuickSpriteImage::QQuickSpriteImage(QQuickItem *parent) :
QQuickItem(parent)
, m_node(0)
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 9f22dfdd08..d7303352c5 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -421,6 +421,10 @@ void QQuickTextPrivate::updateSize()
//setup instance of QTextLayout for all cases other than richtext
if (!richText) {
QRectF textRect = setupTextLayout(&naturalWidth);
+
+ if (internalWidthUpdate) // probably the result of a binding loop, but by letting it
+ return; // get this far we'll get a warning to that effect if it is.
+
layedOutTextRect = textRect;
size = textRect.size();
dy -= size.height();
@@ -443,7 +447,13 @@ void QQuickTextPrivate::updateSize()
if (requireImplicitWidth && q->widthValid()) {
extra->doc->setTextWidth(-1);
naturalWidth = extra->doc->idealWidth();
+ const bool wasInLayout = internalWidthUpdate;
+ internalWidthUpdate = true;
+ q->setImplicitWidth(naturalWidth);
+ internalWidthUpdate = wasInLayout;
}
+ if (internalWidthUpdate)
+ return;
if (wrapMode != QQuickText::NoWrap && q->widthValid())
extra->doc->setTextWidth(q->width());
else
@@ -468,8 +478,6 @@ void QQuickTextPrivate::updateSize()
qreal iWidth = -1;
if (!q->widthValid())
iWidth = size.width();
- else if (requireImplicitWidth)
- iWidth = naturalWidth;
if (iWidth > -1)
q->setImplicitSize(iWidth, size.height());
internalWidthUpdate = false;
@@ -697,6 +705,11 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
layout.endLayout();
*naturalWidth = layout.maximumWidth();
layout.clearLayout();
+
+ bool wasInLayout = internalWidthUpdate;
+ internalWidthUpdate = true;
+ q->setImplicitWidth(*naturalWidth);
+ internalWidthUpdate = wasInLayout;
}
QFontMetrics fm(font);
@@ -704,7 +717,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
return QRect(0, 0, 0, height);
}
- const qreal lineWidth = q->widthValid() ? q->width() : FLT_MAX;
+ qreal lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX;
const qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX;
const bool customLayout = isLineLaidOutConnected();
@@ -735,6 +748,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
QTextLine line;
int visibleCount = 0;
bool elide;
+ bool widthChanged;
qreal height = 0;
QString elideText;
bool once = true;
@@ -755,13 +769,14 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
scaledFont.setPointSize(scaledFontSize);
layout.setFont(scaledFont);
}
- layout.beginLayout();
+ layout.beginLayout();
bool wrapped = false;
bool truncateHeight = false;
truncated = false;
elide = false;
+ widthChanged = false;
int characterCount = 0;
int unwrappedLineCount = 1;
int maxLineCount = maximumLineCount();
@@ -864,7 +879,6 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
br = br.united(line.naturalTextRect());
line = nextLine;
}
-
layout.endLayout();
br.moveTop(0);
@@ -886,8 +900,21 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
if (!line.isValid())
break;
}
+
*naturalWidth = qMax(*naturalWidth, widthLayout.maximumWidth());
}
+
+ bool wasInLayout = internalWidthUpdate;
+ internalWidthUpdate = true;
+ q->setImplicitWidth(*naturalWidth);
+ internalWidthUpdate = wasInLayout;
+
+ const qreal oldWidth = lineWidth;
+ lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX;
+ if (lineWidth != oldWidth && (singlelineElide || multilineElide || canWrap || horizontalFit)) {
+ widthChanged = true;
+ continue;
+ }
}
// If the next needs to be elided and there's an abbreviated string available
@@ -911,32 +938,36 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
if (horizontalFit) {
if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
largeFont = scaledFontSize - 1;
- scaledFontSize = (smallFont + largeFont) / 2;
if (smallFont > largeFont)
break;
+ scaledFontSize = (smallFont + largeFont) / 2;
+ if (pixelSize)
+ scaledFont.setPixelSize(scaledFontSize);
+ else
+ scaledFont.setPointSize(scaledFontSize);
continue;
} else if (!verticalFit) {
smallFont = scaledFontSize;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
if (smallFont == largeFont)
break;
+ scaledFontSize = (smallFont + largeFont + 1) / 2;
}
}
if (verticalFit) {
if (truncateHeight || unelidedRect.height() > maxHeight) {
largeFont = scaledFontSize - 1;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
if (smallFont > largeFont)
break;
+ scaledFontSize = (smallFont + largeFont) / 2;
+
} else {
smallFont = scaledFontSize;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
if (smallFont == largeFont)
break;
+ scaledFontSize = (smallFont + largeFont + 1) / 2;
}
}
-
}
if (eos != multilengthEos)
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 9a61312910..1846d03b9b 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -531,29 +531,12 @@ void QQuickTextControlPrivate::extendWordwiseSelection(int suggestedNewPosition,
if (!wordSelectionEnabled && (mouseXPosition < wordStartX || mouseXPosition > wordEndX))
return;
- if (wordSelectionEnabled) {
- if (suggestedNewPosition < selectedWordOnDoubleClick.position()) {
- cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
- setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
- } else {
- cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
- setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
- }
+ if (suggestedNewPosition < selectedWordOnDoubleClick.position()) {
+ cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
+ setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
} else {
- // keep the already selected word even when moving to the left
- // (#39164)
- if (suggestedNewPosition < selectedWordOnDoubleClick.position())
- cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
- else
- cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
-
- const qreal differenceToStart = mouseXPosition - wordStartX;
- const qreal differenceToEnd = wordEndX - mouseXPosition;
-
- if (differenceToStart < differenceToEnd)
- setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
- else
- setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
+ cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
+ setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
}
if (interactionFlags & Qt::TextSelectableByMouse) {
@@ -594,13 +577,6 @@ void QQuickTextControlPrivate::extendBlockwiseSelection(int suggestedNewPosition
}
}
-void QQuickTextControlPrivate::_q_deleteSelected()
-{
- if (!(interactionFlags & Qt::TextEditable) || !cursor.hasSelection())
- return;
- cursor.removeSelectedText();
-}
-
void QQuickTextControl::undo()
{
Q_D(QQuickTextControl);
@@ -690,14 +666,6 @@ void QQuickTextControl::paste(QClipboard::Mode mode)
}
#endif
-void QQuickTextControl::clear()
-{
- Q_D(QQuickTextControl);
- // clears and sets empty content
- d->setContent();
-}
-
-
void QQuickTextControl::selectAll()
{
Q_D(QQuickTextControl);
@@ -1527,13 +1495,6 @@ QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property) cons
}
}
-void QQuickTextControl::setFocus(bool focus, Qt::FocusReason reason)
-{
- QFocusEvent ev(focus ? QEvent::FocusIn : QEvent::FocusOut,
- reason);
- processEvent(&ev);
-}
-
void QQuickTextControlPrivate::focusEvent(QFocusEvent *e)
{
Q_Q(QQuickTextControl);
@@ -1555,31 +1516,6 @@ void QQuickTextControlPrivate::focusEvent(QFocusEvent *e)
}
}
-QString QQuickTextControlPrivate::anchorForCursor(const QTextCursor &anchorCursor) const
-{
- if (anchorCursor.hasSelection()) {
- QTextCursor cursor = anchorCursor;
- if (cursor.selectionStart() != cursor.position())
- cursor.setPosition(cursor.selectionStart());
- cursor.movePosition(QTextCursor::NextCharacter);
- QTextCharFormat fmt = cursor.charFormat();
- if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref))
- return fmt.stringProperty(QTextFormat::AnchorHref);
- }
- return QString();
-}
-
-QTextCursor QQuickTextControl::cursorForPosition(const QPointF &pos) const
-{
- Q_D(const QQuickTextControl);
- int cursorPos = hitTest(pos, Qt::FuzzyHit);
- if (cursorPos == -1)
- cursorPos = 0;
- QTextCursor c(d->doc);
- c.setPosition(cursorPos);
- return c;
-}
-
QRectF QQuickTextControl::cursorRect(const QTextCursor &cursor) const
{
Q_D(const QQuickTextControl);
@@ -1609,23 +1545,6 @@ QString QQuickTextControl::anchorAt(const QPointF &pos) const
return d->doc->documentLayout()->anchorAt(pos);
}
-QString QQuickTextControl::anchorAtCursor() const
-{
- Q_D(const QQuickTextControl);
-
- return d->anchorForCursor(d->cursor);
-}
-
-int QQuickTextControl::cursorWidth() const
-{
-#ifndef QT_NO_PROPERTIES
- Q_D(const QQuickTextControl);
- return d->doc->documentLayout()->property("cursorWidth").toInt();
-#else
- return 1;
-#endif
-}
-
void QQuickTextControl::setCursorWidth(int width)
{
Q_D(QQuickTextControl);
@@ -1639,36 +1558,12 @@ void QQuickTextControl::setCursorWidth(int width)
d->repaintCursor();
}
-bool QQuickTextControl::acceptRichText() const
-{
- Q_D(const QQuickTextControl);
- return d->acceptRichText;
-}
-
void QQuickTextControl::setAcceptRichText(bool accept)
{
Q_D(QQuickTextControl);
d->acceptRichText = accept;
}
-void QQuickTextControl::setTextWidth(qreal width)
-{
- Q_D(QQuickTextControl);
- d->doc->setTextWidth(width);
-}
-
-qreal QQuickTextControl::textWidth() const
-{
- Q_D(const QQuickTextControl);
- return d->doc->textWidth();
-}
-
-QSizeF QQuickTextControl::size() const
-{
- Q_D(const QQuickTextControl);
- return d->doc->size();
-}
-
void QQuickTextControl::moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
{
Q_D(QQuickTextControl);
@@ -1700,24 +1595,12 @@ void QQuickTextControl::setCursorIsFocusIndicator(bool b)
d->repaintCursor();
}
-bool QQuickTextControl::cursorIsFocusIndicator() const
-{
- Q_D(const QQuickTextControl);
- return d->cursorIsFocusIndicator;
-}
-
void QQuickTextControl::setWordSelectionEnabled(bool enabled)
{
Q_D(QQuickTextControl);
d->wordSelectionEnabled = enabled;
}
-bool QQuickTextControl::isWordSelectionEnabled() const
-{
- Q_D(const QQuickTextControl);
- return d->wordSelectionEnabled;
-}
-
QMimeData *QQuickTextControl::createMimeDataFromSelection() const
{
Q_D(const QQuickTextControl);
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index 97ecdc4c6e..9e3fc90eb1 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -80,12 +80,6 @@ class Q_AUTOTEST_EXPORT QQuickTextControl : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickTextControl)
-#ifndef QT_NO_TEXTHTMLPARSER
- Q_PROPERTY(QString html READ toHtml WRITE setHtml NOTIFY textChanged USER true)
-#endif
- Q_PROPERTY(bool acceptRichText READ acceptRichText WRITE setAcceptRichText)
- Q_PROPERTY(int cursorWidth READ cursorWidth WRITE setCursorWidth)
- Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlags WRITE setTextInteractionFlags)
public:
explicit QQuickTextControl(QTextDocument *doc, QObject *parent = 0);
virtual ~QQuickTextControl();
@@ -104,7 +98,6 @@ public:
QString toHtml() const;
#endif
- QTextCursor cursorForPosition(const QPointF &pos) const;
QRectF cursorRect(const QTextCursor &cursor) const;
QRectF cursorRect() const;
QRectF selectionRect(const QTextCursor &cursor) const;
@@ -112,26 +105,15 @@ public:
QString anchorAt(const QPointF &pos) const;
- QString anchorAtCursor() const;
-
- int cursorWidth() const;
void setCursorWidth(int width);
- bool acceptRichText() const;
void setAcceptRichText(bool accept);
- void setTextWidth(qreal width);
- qreal textWidth() const;
- QSizeF size() const;
-
void moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor);
bool canPaste() const;
void setCursorIsFocusIndicator(bool b);
- bool cursorIsFocusIndicator() const;
-
- bool isWordSelectionEnabled() const;
void setWordSelectionEnabled(bool enabled);
virtual int hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const;
@@ -151,7 +133,6 @@ public Q_SLOTS:
void undo();
void redo();
- void clear();
void selectAll();
Q_SIGNALS:
@@ -175,9 +156,6 @@ public:
virtual void processEvent(QEvent *e, const QMatrix &matrix);
void processEvent(QEvent *e, const QPointF &coordinateOffset = QPointF());
- // control methods
- void setFocus(bool focus, Qt::FocusReason = Qt::OtherFocusReason);
-
virtual QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
virtual QMimeData *createMimeDataFromSelection() const;
@@ -195,7 +173,6 @@ private:
Q_DISABLE_COPY(QQuickTextControl)
Q_PRIVATE_SLOT(d_func(), void _q_updateCurrentCharFormatAndSelection())
Q_PRIVATE_SLOT(d_func(), void _q_emitCursorPosChanged(const QTextCursor &))
- Q_PRIVATE_SLOT(d_func(), void _q_deleteSelected())
Q_PRIVATE_SLOT(d_func(), void _q_updateBlock(const QTextBlock &))
Q_PRIVATE_SLOT(d_func(), void _q_documentLayoutChanged())
};
diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h
index 44bc00221b..9d776ce46b 100644
--- a/src/quick/items/qquicktextcontrol_p_p.h
+++ b/src/quick/items/qquicktextcontrol_p_p.h
@@ -106,8 +106,6 @@ public:
void extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition);
void extendBlockwiseSelection(int suggestedNewPosition);
- void _q_deleteSelected();
-
void _q_setCursorAfterUndoRedo(int undoPosition, int charsAdded, int charsRemoved);
QRectF cursorRectPlusUnicodeDirectionMarkers(const QTextCursor &cursor) const;
@@ -116,8 +114,6 @@ public:
inline QRectF selectionRect() const
{ return selectionRect(this->cursor); }
- QString anchorForCursor(const QTextCursor &anchor) const;
-
void keyPressEvent(QKeyEvent *e);
void mousePressEvent(QMouseEvent *event, const QPointF &pos);
void mouseMoveEvent(QMouseEvent *event, const QPointF &pos);
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 5456d3523a..4fa5233b9a 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -1143,7 +1143,8 @@ void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints)
void QQuickTextEdit::geometryChanged(const QRectF &newGeometry,
const QRectF &oldGeometry)
{
- if (newGeometry.width() != oldGeometry.width())
+ Q_D(QQuickTextEdit);
+ if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap && !d->inLayout)
updateSize();
QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
}
@@ -1477,6 +1478,7 @@ Handles the given mouse \a event.
void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
if (d->focusOnPress){
bool hadActiveFocus = hasActiveFocus();
forceActiveFocus();
@@ -1484,7 +1486,6 @@ void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
openSoftwareInputPanel();
}
- d->control->processEvent(event, QPointF(0, -d->yoff));
if (!event->isAccepted())
QQuickImplicitSizeItem::mousePressEvent(event);
}
@@ -1857,6 +1858,13 @@ void QQuickTextEdit::updateSize()
if (d->requireImplicitWidth) {
d->document->setTextWidth(-1);
naturalWidth = d->document->idealWidth();
+
+ const bool wasInLayout = d->inLayout;
+ d->inLayout = true;
+ setImplicitWidth(naturalWidth);
+ d->inLayout = wasInLayout;
+ if (d->inLayout) // probably the result of a binding loop, but by letting it
+ return; // get this far we'll get a warning to that effect.
}
if (d->document->textWidth() != width())
d->document->setTextWidth(width());
@@ -1888,11 +1896,11 @@ void QQuickTextEdit::updateSize()
d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
// ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
qreal iWidth = -1;
- if (!widthValid())
+ if (!widthValid() && !d->requireImplicitWidth)
iWidth = newWidth;
- else if (d->requireImplicitWidth)
- iWidth = naturalWidth;
+
qreal newHeight = d->document->isEmpty() ? fm.height() : d->document->size().height();
+
if (iWidth > -1)
setImplicitSize(iWidth, newHeight);
else
diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h
index 055b5c7929..f0a35d5266 100644
--- a/src/quick/items/qquicktextedit_p_p.h
+++ b/src/quick/items/qquicktextedit_p_p.h
@@ -78,7 +78,7 @@ public:
, documentDirty(true), dirty(false), richText(false), cursorVisible(false)
, focusOnPress(true), persistentSelection(false), requireImplicitWidth(false)
, selectByMouse(false), canPaste(false), canPasteValid(false), hAlignImplicit(true)
- , rightToLeftText(false), textCached(false)
+ , rightToLeftText(false), textCached(false), inLayout(false)
{
}
@@ -144,6 +144,7 @@ public:
bool hAlignImplicit:1;
bool rightToLeftText:1;
bool textCached:1;
+ bool inLayout:1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 0b21d6b169..94856b63ab 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -1444,13 +1444,9 @@ void QQuickTextInput::mousePressEvent(QMouseEvent *event)
d->pressPos = event->localPos();
- if (d->focusOnPress) {
- bool hadActiveFocus = hasActiveFocus();
- forceActiveFocus();
- // re-open input panel on press if already focused
- if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
- openSoftwareInputPanel();
- }
+ if (d->sendMouseEventToInputContext(event))
+ return;
+
if (d->selectByMouse) {
setKeepMouseGrab(false);
d->selectPressed = true;
@@ -1463,12 +1459,18 @@ void QQuickTextInput::mousePressEvent(QMouseEvent *event)
}
}
- if (d->sendMouseEventToInputContext(event))
- return;
-
bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
int cursor = d->positionAt(event->localPos());
d->moveCursor(cursor, mark);
+
+ if (d->focusOnPress) {
+ bool hadActiveFocus = hasActiveFocus();
+ forceActiveFocus();
+ // re-open input panel on press if already focused
+ if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
+ openSoftwareInputPanel();
+ }
+
event->setAccepted(true);
}
@@ -1602,9 +1604,11 @@ void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
const QRectF &oldGeometry)
{
Q_D(QQuickTextInput);
- if (newGeometry.width() != oldGeometry.width())
- d->updateLayout();
- updateCursorRectangle();
+ if (!d->inLayout) {
+ if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
+ d->updateLayout();
+ updateCursorRectangle();
+ }
QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
}
@@ -1614,14 +1618,19 @@ void QQuickTextInputPrivate::updateHorizontalScroll()
QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
const int preeditLength = m_textLayout.preeditAreaText().length();
const qreal width = qMax<qreal>(0, q->width());
- qreal widthUsed = currentLine.isValid() ? currentLine.naturalTextWidth() : 0;
+ qreal cix = 0;
+ qreal widthUsed = 0;
+ if (currentLine.isValid()) {
+ cix = currentLine.cursorToX(m_cursor + preeditLength);
+ const qreal cursorWidth = cix >= 0 ? cix : width - cix;
+ widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
+ }
int previousScroll = hscroll;
if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
hscroll = 0;
} else {
Q_ASSERT(currentLine.isValid());
- qreal cix = currentLine.cursorToX(m_cursor + preeditLength);
if (cix - hscroll >= width) {
// text doesn't fit, cursor is to the right of br (scroll right)
hscroll = cix - width;
@@ -1632,6 +1641,10 @@ void QQuickTextInputPrivate::updateHorizontalScroll()
// text doesn't fit, text document is to the left of br; align
// right
hscroll = widthUsed - width;
+ } else if (width - hscroll > widthUsed) {
+ // text doesn't fit, text document is to the right of br; align
+ // left
+ hscroll = width - widthUsed;
}
if (preeditLength > 0) {
// check to ensure long pre-edit text doesn't push the cursor
@@ -2688,6 +2701,38 @@ void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
}
}
+qreal QQuickTextInputPrivate::getImplicitWidth() const
+{
+ Q_Q(const QQuickTextInput);
+ if (!requireImplicitWidth) {
+ QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
+ d->requireImplicitWidth = true;
+
+ if (q->isComponentComplete()) {
+ // One time cost, only incurred if implicitWidth is first requested after
+ // componentComplete.
+ QTextLayout layout(m_text);
+
+ QTextOption option = m_textLayout.textOption();
+ option.setTextDirection(m_layoutDirection);
+ option.setFlags(QTextOption::IncludeTrailingSpaces);
+ option.setWrapMode(QTextOption::WrapMode(wrapMode));
+ option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
+ layout.setTextOption(option);
+ layout.setFont(font);
+ layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
+ layout.beginLayout();
+
+ QTextLine line = layout.createLine();
+ line.setLineWidth(INT_MAX);
+ d->implicitWidth = qCeil(line.naturalTextWidth());
+
+ layout.endLayout();
+ }
+ }
+ return implicitWidth;
+}
+
void QQuickTextInputPrivate::updateLayout()
{
Q_Q(QQuickTextInput);
@@ -2699,7 +2744,6 @@ void QQuickTextInputPrivate::updateLayout()
QTextOption option = m_textLayout.textOption();
option.setTextDirection(layoutDirection());
- option.setFlags(QTextOption::IncludeTrailingSpaces);
option.setWrapMode(QTextOption::WrapMode(wrapMode));
option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
m_textLayout.setTextOption(option);
@@ -2708,9 +2752,17 @@ void QQuickTextInputPrivate::updateLayout()
boundingRect = QRectF();
m_textLayout.beginLayout();
QTextLine line = m_textLayout.createLine();
+ if (requireImplicitWidth) {
+ line.setLineWidth(INT_MAX);
+ const bool wasInLayout = inLayout;
+ inLayout = true;
+ q->setImplicitWidth(qCeil(line.naturalTextWidth()));
+ inLayout = wasInLayout;
+ if (inLayout) // probably the result of a binding loop, but by letting it
+ return; // get this far we'll get a warning to that effect.
+ }
qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
qreal height = 0;
- QTextLine firstLine = line;
do {
line.setLineWidth(lineWidth);
line.setPosition(QPointF(line.position().x(), height));
@@ -2728,7 +2780,11 @@ void QQuickTextInputPrivate::updateLayout()
updateType = UpdatePaintNode;
q->update();
- q->setImplicitSize(boundingRect.width(), boundingRect.height());
+
+ if (!requireImplicitWidth && !q->widthValid())
+ q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
+ else
+ q->setImplicitHeight(qCeil(boundingRect.height()));
if (previousRect != boundingRect)
emit q->contentSizeChanged();
@@ -3261,7 +3317,14 @@ void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool e
m_textDirty = (oldText != m_text);
bool changed = finishChange(-1, true, edited);
+#ifdef QT_NO_ACCESSIBILITY
Q_UNUSED(changed)
+#else
+ if (changed) {
+ QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
}
@@ -3885,6 +3948,11 @@ bool QQuickTextInputPrivate::emitCursorPositionChanged()
}
}
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessibleTextCursorEvent ev(q, m_cursor);
+ QAccessible::updateAccessibility(&ev);
+#endif
+
return true;
}
return false;
@@ -3964,12 +4032,10 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
}
#ifndef QT_NO_SHORTCUT
else if (event == QKeySequence::Undo) {
- if (!m_readOnly)
- q->undo();
+ q->undo();
}
else if (event == QKeySequence::Redo) {
- if (!m_readOnly)
- q->redo();
+ q->redo();
}
else if (event == QKeySequence::SelectAll) {
selectAll();
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index bb00600661..165155acd0 100644
--- a/src/quick/items/qquicktextinput_p_p.h
+++ b/src/quick/items/qquicktextinput_p_p.h
@@ -125,6 +125,8 @@ public:
, m_acceptableInput(1)
, m_blinkStatus(0)
, m_passwordEchoEditing(false)
+ , inLayout(false)
+ , requireImplicitWidth(false)
{
}
@@ -256,7 +258,8 @@ public:
bool m_acceptableInput : 1;
bool m_blinkStatus : 1;
bool m_passwordEchoEditing : 1;
-
+ bool inLayout:1;
+ bool requireImplicitWidth:1;
static inline QQuickTextInputPrivate *get(QQuickTextInput *t) {
return t->d_func();
@@ -404,6 +407,8 @@ public:
void updateLayout();
+ qreal getImplicitWidth() const;
+
private:
void removeSelectedText();
void internalSetText(const QString &txt, int pos = -1, bool edited = true);
diff --git a/src/quick/items/qquickvisualadaptormodel.cpp b/src/quick/items/qquickvisualadaptormodel.cpp
index 622adf4ce9..cd9db7235b 100644
--- a/src/quick/items/qquickvisualadaptormodel.cpp
+++ b/src/quick/items/qquickvisualadaptormodel.cpp
@@ -65,7 +65,8 @@ public:
}
VDMDelegateDataType(const VDMDelegateDataType &type)
- : metaObject(0)
+ : QQmlRefCount()
+ , metaObject(0)
, propertyCache(0)
, propertyOffset(type.propertyOffset)
, signalOffset(type.signalOffset)
diff --git a/src/quick/items/qquickwindowmanager.cpp b/src/quick/items/qquickwindowmanager.cpp
index 64eb2bf53b..61c2ef24b4 100644
--- a/src/quick/items/qquickwindowmanager.cpp
+++ b/src/quick/items/qquickwindowmanager.cpp
@@ -228,7 +228,7 @@ public slots:
private:
void handleAddedWindows();
void handleAddedWindow(QQuickCanvas *canvas);
- void handleRemovedWindows();
+ void handleRemovedWindows(bool clearGLContext = true);
QSGContext *sg;
QOpenGLContext *gl;
@@ -475,7 +475,7 @@ void QQuickRenderThreadSingleContextWindowManager::hide(QQuickCanvas *canvas)
/*!
Called on Render Thread
*/
-void QQuickRenderThreadSingleContextWindowManager::handleRemovedWindows()
+void QQuickRenderThreadSingleContextWindowManager::handleRemovedWindows(bool clearGLContext)
{
#ifdef THREAD_DEBUG
printf(" RenderThread: about to remove %d\n", m_removed_windows.size());
@@ -496,7 +496,7 @@ void QQuickRenderThreadSingleContextWindowManager::handleRemovedWindows()
// If a window is removed because it has been hidden it will take with it
// the gl context (at least on Mac) if bound, so disconnect the gl context
// from anything
- if (removedAnything)
+ if (removedAnything && clearGLContext)
gl->doneCurrent();
}
@@ -755,7 +755,7 @@ void QQuickRenderThreadSingleContextWindowManager::run()
#endif
m_removed_windows << m_rendered_windows.keys();
- handleRemovedWindows();
+ handleRemovedWindows(false);
sg->invalidate();
diff --git a/src/quick/particles/qquickangledirection.cpp b/src/quick/particles/qquickangledirection.cpp
index a3bd45e0bf..e77c47362c 100644
--- a/src/quick/particles/qquickangledirection.cpp
+++ b/src/quick/particles/qquickangledirection.cpp
@@ -42,6 +42,9 @@
#include "qquickangledirection_p.h"
#include <stdlib.h>
#include <cmath>
+#ifdef Q_OS_QNX
+#include <math.h>
+#endif
QT_BEGIN_NAMESPACE
const qreal CONV = 0.017453292519943295;
/*!
diff --git a/src/quick/particles/qquickcustomparticle.cpp b/src/quick/particles/qquickcustomparticle.cpp
index a8f146ad05..8f75672e32 100644
--- a/src/quick/particles/qquickcustomparticle.cpp
+++ b/src/quick/particles/qquickcustomparticle.cpp
@@ -139,6 +139,12 @@ QQuickCustomParticle::QQuickCustomParticle(QQuickItem* parent)
class QQuickShaderEffectMaterialObject : public QObject, public QQuickShaderEffectMaterial { };
+void QQuickCustomParticle::sceneGraphInvalidated()
+{
+ m_nodes.clear();
+ m_rootNode = 0;
+}
+
QQuickCustomParticle::~QQuickCustomParticle()
{
if (m_material)
diff --git a/src/quick/particles/qquickcustomparticle_p.h b/src/quick/particles/qquickcustomparticle_p.h
index 29f3d19657..e04ac704d0 100644
--- a/src/quick/particles/qquickcustomparticle_p.h
+++ b/src/quick/particles/qquickcustomparticle_p.h
@@ -93,6 +93,8 @@ protected:
QQuickShaderEffectNode *buildCustomNodes();
void performPendingResize();
+ void sceneGraphInvalidated();
+
private:
void buildData();
diff --git a/src/quick/particles/qquickellipseextruder.cpp b/src/quick/particles/qquickellipseextruder.cpp
index 3eb547fd2f..083564e5cb 100644
--- a/src/quick/particles/qquickellipseextruder.cpp
+++ b/src/quick/particles/qquickellipseextruder.cpp
@@ -42,6 +42,11 @@
#include "qquickellipseextruder_p.h"
#include <stdlib.h>
#include <cmath>
+
+#ifdef Q_OS_QNX
+#include <math.h>
+#endif
+
QT_BEGIN_NAMESPACE
/*!
\qmlclass EllipseShape QQuickEllipseExtruder
diff --git a/src/quick/particles/qquickimageparticle.cpp b/src/quick/particles/qquickimageparticle.cpp
index 386892a12a..d9eb6ed01b 100644
--- a/src/quick/particles/qquickimageparticle.cpp
+++ b/src/quick/particles/qquickimageparticle.cpp
@@ -839,6 +839,13 @@ QQmlListProperty<QQuickSprite> QQuickImageParticle::sprites()
return QQmlListProperty<QQuickSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
}
+void QQuickImageParticle::sceneGraphInvalidated()
+{
+ m_nodes.clear();
+ m_rootNode = 0;
+ m_material = 0;
+}
+
void QQuickImageParticle::setImage(const QUrl &image)
{
if (image.isEmpty()){
diff --git a/src/quick/particles/qquickimageparticle_p.h b/src/quick/particles/qquickimageparticle_p.h
index dca524bcab..4db2c9801a 100644
--- a/src/quick/particles/qquickimageparticle_p.h
+++ b/src/quick/particles/qquickimageparticle_p.h
@@ -348,6 +348,8 @@ protected:
void prepareNextFrame();
void buildParticleNodes();
+ void sceneGraphInvalidated();
+
private slots:
void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty
diff --git a/src/quick/particles/qquickparticleemitter.cpp b/src/quick/particles/qquickparticleemitter.cpp
index 0f7f3817f2..035d66cbcd 100644
--- a/src/quick/particles/qquickparticleemitter.cpp
+++ b/src/quick/particles/qquickparticleemitter.cpp
@@ -284,23 +284,17 @@ QQuickParticleExtruder* QQuickParticleEmitter::effectiveExtruder()
void QQuickParticleEmitter::pulse(int milliseconds)
{
- if (!particleCount())
- qWarning() << "pulse called on an emitter with a particle count of zero";
if (!m_enabled)
m_pulseLeft = milliseconds;
}
void QQuickParticleEmitter::burst(int num)
{
- if (!particleCount())
- qWarning() << "burst called on an emitter with a particle count of zero";
m_burstQueue << qMakePair(num, QPointF(x(), y()));
}
void QQuickParticleEmitter::burst(int num, qreal x, qreal y)
{
- if (!particleCount())
- qWarning() << "burst called on an emitter with a particle count of zero";
m_burstQueue << qMakePair(num, QPointF(x, y));
}
diff --git a/src/quick/particles/qquickparticlepainter.cpp b/src/quick/particles/qquickparticlepainter.cpp
index f46f2f2235..e490b70240 100644
--- a/src/quick/particles/qquickparticlepainter.cpp
+++ b/src/quick/particles/qquickparticlepainter.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qquickparticlepainter_p.h"
+#include <QQuickCanvas>
#include <QDebug>
QT_BEGIN_NAMESPACE
/*!
@@ -65,10 +66,22 @@ QT_BEGIN_NAMESPACE
*/
QQuickParticlePainter::QQuickParticlePainter(QQuickItem *parent) :
QQuickItem(parent),
- m_system(0), m_count(0), m_pleaseReset(true)
+ m_system(0), m_count(0), m_pleaseReset(true), m_canvas(0)
{
}
+void QQuickParticlePainter::itemChange(ItemChange change, const ItemChangeData &data)
+{
+ if (change == QQuickItem::ItemSceneChange) {
+ if (m_canvas)
+ disconnect(m_canvas, SIGNAL(sceneGraphInvalidated()), this, SLOT(sceneGraphInvalidated()));
+ m_canvas = data.canvas;
+ if (m_canvas)
+ connect(m_canvas, SIGNAL(sceneGraphInvalidated()), this, SLOT(sceneGraphInvalidated()), Qt::DirectConnection);
+
+ }
+}
+
void QQuickParticlePainter::componentComplete()
{
if (!m_system && qobject_cast<QQuickParticleSystem*>(parentItem()))
diff --git a/src/quick/particles/qquickparticlepainter_p.h b/src/quick/particles/qquickparticlepainter_p.h
index ebe76d98ea..1ae4625856 100644
--- a/src/quick/particles/qquickparticlepainter_p.h
+++ b/src/quick/particles/qquickparticlepainter_p.h
@@ -76,6 +76,8 @@ public:
return m_groups;
}
+ void itemChange(ItemChange, const ItemChangeData &);
+
signals:
void countChanged();
void systemChanged(QQuickParticleSystem* arg);
@@ -96,6 +98,9 @@ public slots:
void calcSystemOffset(bool resetPending = false);
+private slots:
+ virtual void sceneGraphInvalidated() {}
+
protected:
/* Reset resets all your internal data structures. But anything attached to a particle should
be in attached data. So reset + reloads should have no visible effect.
@@ -121,6 +126,8 @@ protected:
QStringList m_groups;
QPointF m_systemOffset;
+ QQuickCanvas *m_canvas;
+
private:
QSet<QPair<int,int> > m_pendingCommits;
};
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp
index dbac95acd1..cf39c308e7 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.cpp
+++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp
@@ -46,6 +46,10 @@
#include <qopenglfunctions.h>
#include <private/qopenglextensions_p.h>
+#ifdef Q_OS_QNX
+#include <malloc.h>
+#endif
+
QT_BEGIN_NAMESPACE
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index 9608ebe861..c78e243dcd 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -45,31 +45,28 @@
#include <QtQuick/private/qsgdistancefieldutil_p.h>
#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
#include <private/qrawfont_p.h>
-#include <private/qdistancefield_p.h>
#include <QtGui/qguiapplication.h>
#include <qdir.h>
QT_BEGIN_NAMESPACE
-QHash<QString, QOpenGLMultiGroupSharedResource> QSGDistanceFieldGlyphCache::m_caches_data;
+QSGDistanceFieldGlyphCache::Texture QSGDistanceFieldGlyphCache::s_emptyTexture;
QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font)
: ctx(c)
, m_manager(man)
+ , m_pendingGlyphs(64)
{
Q_ASSERT(font.isValid());
- m_font = font;
- m_cacheData = cacheData();
-
- QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ QRawFontPrivate *fontD = QRawFontPrivate::get(font);
m_glyphCount = fontD->fontEngine->glyphCount();
- m_cacheData->doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT;
+ m_doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT;
- m_referenceFont = m_font;
- m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(m_cacheData->doubleGlyphResolution));
+ m_referenceFont = font;
+ m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution));
Q_ASSERT(m_referenceFont.isValid());
}
@@ -77,58 +74,31 @@ QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
{
}
-QSGDistanceFieldGlyphCache::GlyphCacheData *QSGDistanceFieldGlyphCache::cacheData()
-{
- QString key = QString::fromLatin1("%1_%2_%3_%4")
- .arg(m_font.familyName())
- .arg(m_font.styleName())
- .arg(m_font.weight())
- .arg(m_font.style());
- return m_caches_data[key].value<QSGDistanceFieldGlyphCache::GlyphCacheData>(ctx);
-}
-
-qreal QSGDistanceFieldGlyphCache::fontScale() const
+QSGDistanceFieldGlyphCache::GlyphData &QSGDistanceFieldGlyphCache::glyphData(glyph_t glyph)
{
- return qreal(m_font.pixelSize()) / QT_DISTANCEFIELD_BASEFONTSIZE(m_cacheData->doubleGlyphResolution);
-}
-
-int QSGDistanceFieldGlyphCache::distanceFieldRadius() const
-{
- return QT_DISTANCEFIELD_DEFAULT_RADIUS / QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution);
-}
-
-QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph)
-{
- QHash<glyph_t, Metrics>::iterator metric = m_metrics.find(glyph);
- if (metric == m_metrics.end()) {
- QPainterPath path = m_font.pathForGlyph(glyph);
- QRectF br = path.boundingRect();
-
- Metrics m;
- m.width = br.width();
- m.height = br.height();
- m.baselineX = br.x();
- m.baselineY = -br.y();
-
- metric = m_metrics.insert(glyph, m);
+ QHash<glyph_t, GlyphData>::iterator data = m_glyphsData.find(glyph);
+ if (data == m_glyphsData.end()) {
+ GlyphData gd;
+ gd.texture = &s_emptyTexture;
+ QPainterPath path = m_referenceFont.pathForGlyph(glyph);
+ gd.boundingRect = path.boundingRect();
+ data = m_glyphsData.insert(glyph, gd);
}
-
- return metric.value();
+ return data.value();
}
-QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph) const
+QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph, qreal pixelSize)
{
- return m_cacheData->texCoords.value(glyph);
-}
+ GlyphData &gd = glyphData(glyph);
+ qreal scale = fontScale(pixelSize);
-static QSGDistanceFieldGlyphCache::Texture g_emptyTexture;
+ Metrics m;
+ m.width = gd.boundingRect.width() * scale;
+ m.height = gd.boundingRect.height() * scale;
+ m.baselineX = gd.boundingRect.x() * scale;
+ m.baselineY = -gd.boundingRect.y() * scale;
-const QSGDistanceFieldGlyphCache::Texture *QSGDistanceFieldGlyphCache::glyphTexture(glyph_t glyph) const
-{
- QHash<glyph_t, Texture*>::const_iterator it = m_cacheData->glyphTextures.find(glyph);
- if (it == m_cacheData->glyphTextures.constEnd())
- return &g_emptyTexture;
- return it.value();
+ return m;
}
void QSGDistanceFieldGlyphCache::populate(const QVector<glyph_t> &glyphs)
@@ -143,23 +113,18 @@ void QSGDistanceFieldGlyphCache::populate(const QVector<glyph_t> &glyphs)
continue;
}
- ++m_cacheData->glyphRefCount[glyphIndex];
+ GlyphData &gd = glyphData(glyphIndex);
+ ++gd.ref;
referencedGlyphs.insert(glyphIndex);
- if (m_cacheData->texCoords.contains(glyphIndex) || newGlyphs.contains(glyphIndex))
+ if (gd.texCoord.isValid() || newGlyphs.contains(glyphIndex))
continue;
- QPainterPath path = m_referenceFont.pathForGlyph(glyphIndex);
- m_cacheData->glyphPaths.insert(glyphIndex, path);
- if (path.isEmpty()) {
- TexCoord c;
- c.width = 0;
- c.height = 0;
- m_cacheData->texCoords.insert(glyphIndex, c);
- continue;
- }
+ gd.texCoord.width = 0;
+ gd.texCoord.height = 0;
- newGlyphs.insert(glyphIndex);
+ if (!gd.boundingRect.isEmpty())
+ newGlyphs.insert(glyphIndex);
}
if (newGlyphs.isEmpty())
@@ -175,7 +140,8 @@ void QSGDistanceFieldGlyphCache::release(const QVector<glyph_t> &glyphs)
int count = glyphs.count();
for (int i = 0; i < count; ++i) {
glyph_t glyphIndex = glyphs.at(i);
- if (--m_cacheData->glyphRefCount[glyphIndex] == 0 && !glyphTexCoord(glyphIndex).isNull())
+ GlyphData &gd = glyphData(glyphIndex);
+ if (--gd.ref == 0 && !gd.texCoord.isNull())
unusedGlyphs.insert(glyphIndex);
}
releaseGlyphs(unusedGlyphs);
@@ -183,7 +149,7 @@ void QSGDistanceFieldGlyphCache::release(const QVector<glyph_t> &glyphs)
void QSGDistanceFieldGlyphCache::update()
{
- if (m_cacheData->pendingGlyphs.isEmpty())
+ if (m_pendingGlyphs.isEmpty())
return;
QHash<glyph_t, QImage> distanceFields;
@@ -194,16 +160,16 @@ void QSGDistanceFieldGlyphCache::update()
QString tmpPath = QString::fromLatin1("%1/.qt/").arg(QDir::tempPath());
QString keyBase = QString::fromLatin1("%1%2%3_%4_%5_%6.fontblob")
.arg(tmpPath)
- .arg(m_font.familyName())
- .arg(m_font.styleName())
- .arg(m_font.weight())
- .arg(m_font.style());
+ .arg(m_referenceFont.familyName())
+ .arg(m_referenceFont.styleName())
+ .arg(m_referenceFont.weight())
+ .arg(m_referenceFont.style());
if (cacheDistanceFields && !QFile::exists(tmpPath))
QDir(tmpPath).mkpath(tmpPath);
- for (int i = 0; i < m_cacheData->pendingGlyphs.size(); ++i) {
- glyph_t glyphIndex = m_cacheData->pendingGlyphs.at(i);
+ for (int i = 0; i < m_pendingGlyphs.size(); ++i) {
+ glyph_t glyphIndex = m_pendingGlyphs.at(i);
if (cacheDistanceFields) {
QString key = keyBase.arg(glyphIndex);
@@ -219,7 +185,7 @@ void QSGDistanceFieldGlyphCache::update()
}
}
- QImage distanceField = qt_renderDistanceFieldGlyph(m_font, glyphIndex, m_cacheData->doubleGlyphResolution);
+ QImage distanceField = qt_renderDistanceFieldGlyph(m_referenceFont, glyphIndex, m_doubleGlyphResolution);
distanceFields.insert(glyphIndex, distanceField);
if (cacheDistanceFields) {
@@ -230,7 +196,7 @@ void QSGDistanceFieldGlyphCache::update()
}
}
- m_cacheData->pendingGlyphs.reset();
+ m_pendingGlyphs.reset();
storeGlyphs(distanceFields);
}
@@ -242,28 +208,22 @@ void QSGDistanceFieldGlyphCache::setGlyphsPosition(const QList<GlyphPosition> &g
int count = glyphs.count();
for (int i = 0; i < count; ++i) {
GlyphPosition glyph = glyphs.at(i);
+ GlyphData &gd = glyphData(glyph.glyph);
- Q_ASSERT(m_cacheData->glyphPaths.contains(glyph.glyph));
-
- QPainterPath path = m_cacheData->glyphPaths.value(glyph.glyph);
- QRectF br = path.boundingRect();
- TexCoord c;
- c.xMargin = QT_DISTANCEFIELD_RADIUS(m_cacheData->doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution));
- c.yMargin = QT_DISTANCEFIELD_RADIUS(m_cacheData->doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution));
- c.x = glyph.position.x();
- c.y = glyph.position.y();
- c.width = br.width();
- c.height = br.height();
-
- if (m_cacheData->texCoords.contains(glyph.glyph))
+ if (!gd.texCoord.isNull())
invalidatedGlyphs.append(glyph.glyph);
- m_cacheData->texCoords.insert(glyph.glyph, c);
+ gd.texCoord.xMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
+ gd.texCoord.yMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
+ gd.texCoord.x = glyph.position.x();
+ gd.texCoord.y = glyph.position.y();
+ gd.texCoord.width = gd.boundingRect.width();
+ gd.texCoord.height = gd.boundingRect.height();
}
if (!invalidatedGlyphs.isEmpty()) {
- QLinkedList<QSGDistanceFieldGlyphNode *>::iterator it = m_cacheData->m_registeredNodes.begin();
- while (it != m_cacheData->m_registeredNodes.end()) {
+ QLinkedList<QSGDistanceFieldGlyphConsumer *>::iterator it = m_registeredNodes.begin();
+ while (it != m_registeredNodes.end()) {
(*it)->invalidateGlyphs(invalidatedGlyphs);
++it;
}
@@ -287,28 +247,29 @@ void QSGDistanceFieldGlyphCache::processPendingGlyphs()
void QSGDistanceFieldGlyphCache::setGlyphsTexture(const QVector<glyph_t> &glyphs, const Texture &tex)
{
- int i = m_cacheData->textures.indexOf(tex);
+ int i = m_textures.indexOf(tex);
if (i == -1) {
- m_cacheData->textures.append(tex);
- i = m_cacheData->textures.size() - 1;
+ m_textures.append(tex);
+ i = m_textures.size() - 1;
} else {
- m_cacheData->textures[i].size = tex.size;
+ m_textures[i].size = tex.size;
}
- Texture *texture = &(m_cacheData->textures[i]);
+ Texture *texture = &(m_textures[i]);
QVector<quint32> invalidatedGlyphs;
int count = glyphs.count();
for (int j = 0; j < count; ++j) {
glyph_t glyphIndex = glyphs.at(j);
- if (m_cacheData->glyphTextures.contains(glyphIndex))
+ GlyphData &gd = glyphData(glyphIndex);
+ if (gd.texture != &s_emptyTexture)
invalidatedGlyphs.append(glyphIndex);
- m_cacheData->glyphTextures.insert(glyphIndex, texture);
+ gd.texture = texture;
}
if (!invalidatedGlyphs.isEmpty()) {
- QLinkedList<QSGDistanceFieldGlyphNode *>::iterator it = m_cacheData->m_registeredNodes.begin();
- while (it != m_cacheData->m_registeredNodes.end()) {
+ QLinkedList<QSGDistanceFieldGlyphConsumer*>::iterator it = m_registeredNodes.begin();
+ while (it != m_registeredNodes.end()) {
(*it)->invalidateGlyphs(invalidatedGlyphs);
++it;
}
@@ -319,20 +280,14 @@ void QSGDistanceFieldGlyphCache::markGlyphsToRender(const QVector<glyph_t> &glyp
{
int count = glyphs.count();
for (int i = 0; i < count; ++i)
- m_cacheData->pendingGlyphs.add(glyphs.at(i));
-}
-
-void QSGDistanceFieldGlyphCache::removeGlyph(glyph_t glyph)
-{
- m_cacheData->texCoords.remove(glyph);
- m_cacheData->glyphTextures.remove(glyph);
+ m_pendingGlyphs.add(glyphs.at(i));
}
void QSGDistanceFieldGlyphCache::updateTexture(GLuint oldTex, GLuint newTex, const QSize &newTexSize)
{
- int count = m_cacheData->textures.count();
+ int count = m_textures.count();
for (int i = 0; i < count; ++i) {
- Texture &tex = m_cacheData->textures[i];
+ Texture &tex = m_textures[i];
if (tex.textureId == oldTex) {
tex.textureId = newTex;
tex.size = newTexSize;
@@ -341,20 +296,4 @@ void QSGDistanceFieldGlyphCache::updateTexture(GLuint oldTex, GLuint newTex, con
}
}
-bool QSGDistanceFieldGlyphCache::containsGlyph(glyph_t glyph) const
-{
- return m_cacheData->texCoords.contains(glyph);
-}
-
-void QSGDistanceFieldGlyphCache::registerGlyphNode(QSGDistanceFieldGlyphNode *node)
-{
- m_cacheData->m_registeredNodes.append(node);
-}
-
-void QSGDistanceFieldGlyphCache::unregisterGlyphNode(QSGDistanceFieldGlyphNode *node)
-{
- m_cacheData->m_registeredNodes.removeOne(node);
-}
-
-
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 47dfdb4d8c..77cd814ce8 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -54,6 +54,7 @@
#include <private/qfontengine_p.h>
#include <QtGui/private/qdatabuffer_p.h>
#include <private/qopenglcontext_p.h>
+#include <private/qdistancefield_p.h>
// ### remove
#include <QtQuick/private/qquicktext_p.h>
@@ -133,6 +134,14 @@ protected:
QQuickItem *m_ownerElement;
};
+class Q_QUICK_EXPORT QSGDistanceFieldGlyphConsumer
+{
+public:
+ virtual ~QSGDistanceFieldGlyphConsumer() {}
+
+ virtual void invalidateGlyphs(const QVector<quint32> &glyphs) = 0;
+};
+
class Q_QUICK_EXPORT QSGDistanceFieldGlyphCache
{
public:
@@ -172,24 +181,30 @@ public:
const QSGDistanceFieldGlyphCacheManager *manager() const { return m_manager; }
- const QRawFont &font() const { return m_font; }
+ const QRawFont &referenceFont() const { return m_referenceFont; }
- qreal fontScale() const;
- int distanceFieldRadius() const;
+ qreal fontScale(qreal pixelSize) const
+ {
+ return pixelSize / QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution);
+ }
+ int distanceFieldRadius() const
+ {
+ return QT_DISTANCEFIELD_DEFAULT_RADIUS / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
+ }
int glyphCount() const { return m_glyphCount; }
- bool doubleGlyphResolution() const { return m_cacheData->doubleGlyphResolution; }
+ bool doubleGlyphResolution() const { return m_doubleGlyphResolution; }
- Metrics glyphMetrics(glyph_t glyph);
- TexCoord glyphTexCoord(glyph_t glyph) const;
- const Texture *glyphTexture(glyph_t glyph) const;
+ Metrics glyphMetrics(glyph_t glyph, qreal pixelSize);
+ inline TexCoord glyphTexCoord(glyph_t glyph);
+ inline const Texture *glyphTexture(glyph_t glyph);
void populate(const QVector<glyph_t> &glyphs);
void release(const QVector<glyph_t> &glyphs);
void update();
- void registerGlyphNode(QSGDistanceFieldGlyphNode *node);
- void unregisterGlyphNode(QSGDistanceFieldGlyphNode *node);
+ void registerGlyphNode(QSGDistanceFieldGlyphConsumer *node) { m_registeredNodes.append(node); }
+ void unregisterGlyphNode(QSGDistanceFieldGlyphConsumer *node) { m_registeredNodes.removeOne(node); }
virtual void registerOwnerElement(QQuickItem *ownerElement);
virtual void unregisterOwnerElement(QQuickItem *ownerElement);
@@ -209,57 +224,64 @@ protected:
void setGlyphsPosition(const QList<GlyphPosition> &glyphs);
void setGlyphsTexture(const QVector<glyph_t> &glyphs, const Texture &tex);
void markGlyphsToRender(const QVector<glyph_t> &glyphs);
- void removeGlyph(glyph_t glyph);
+ inline void removeGlyph(glyph_t glyph);
void updateTexture(GLuint oldTex, GLuint newTex, const QSize &newTexSize);
- bool containsGlyph(glyph_t glyph) const;
+ inline bool containsGlyph(glyph_t glyph);
GLuint textureIdForGlyph(glyph_t glyph) const;
QOpenGLContext *ctx;
private:
- struct GlyphCacheData : public QOpenGLSharedResource {
- QList<Texture> textures;
- QHash<glyph_t, Texture*> glyphTextures;
- QHash<glyph_t, TexCoord> texCoords;
- QDataBuffer<glyph_t> pendingGlyphs;
- QHash<glyph_t, QPainterPath> glyphPaths;
- bool doubleGlyphResolution;
- QLinkedList<QSGDistanceFieldGlyphNode*> m_registeredNodes;
- QHash<glyph_t, quint32> glyphRefCount;
-
- GlyphCacheData(QOpenGLContext *ctx)
- : QOpenGLSharedResource(ctx->shareGroup())
- , pendingGlyphs(64)
- , doubleGlyphResolution(false)
- {}
-
- void invalidateResource()
- {
- textures.clear();
- glyphTextures.clear();
- texCoords.clear();
- }
-
- void freeResource(QOpenGLContext *)
- {
- }
+ struct GlyphData {
+ Texture *texture;
+ TexCoord texCoord;
+ QRectF boundingRect;
+ quint32 ref;
+
+ GlyphData() : texture(0), ref(0) { }
};
+ GlyphData &glyphData(glyph_t glyph);
+
QSGDistanceFieldGlyphCacheManager *m_manager;
- QRawFont m_font;
QRawFont m_referenceFont;
-
int m_glyphCount;
- QHash<glyph_t, Metrics> m_metrics;
- GlyphCacheData *cacheData();
- GlyphCacheData *m_cacheData;
- static QHash<QString, QOpenGLMultiGroupSharedResource> m_caches_data;
+ bool m_doubleGlyphResolution;
+
+ QList<Texture> m_textures;
+ QHash<glyph_t, GlyphData> m_glyphsData;
+ QDataBuffer<glyph_t> m_pendingGlyphs;
+ QLinkedList<QSGDistanceFieldGlyphConsumer*> m_registeredNodes;
+
+ static Texture s_emptyTexture;
};
+inline QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph)
+{
+ return glyphData(glyph).texCoord;
+}
+
+inline const QSGDistanceFieldGlyphCache::Texture *QSGDistanceFieldGlyphCache::glyphTexture(glyph_t glyph)
+{
+ return glyphData(glyph).texture;
+}
+
+inline void QSGDistanceFieldGlyphCache::removeGlyph(glyph_t glyph)
+{
+ GlyphData &gd = glyphData(glyph);
+ gd.texCoord = TexCoord();
+ gd.texture = &s_emptyTexture;
+}
+
+inline bool QSGDistanceFieldGlyphCache::containsGlyph(glyph_t glyph)
+{
+ return glyphData(glyph).texCoord.isValid();
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index 02fbaa1a7f..da1c8e6ee9 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -54,6 +54,7 @@
#include <QGuiApplication>
#include <QOpenGLContext>
+#include <QtGui/qopenglframebufferobject.h>
#include <private/qqmlglobal_p.h>
@@ -95,7 +96,13 @@ class QSGContextPrivate : public QObjectPrivate
public:
QSGContextPrivate()
: gl(0)
+ , depthStencilBufferManager(0)
, distanceFieldCacheManager(0)
+ #ifndef QT_OPENGL_ES
+ , distanceFieldAntialiasing(QSGGlyphNode::HighQualitySubPixelAntialiasing)
+ #else
+ , distanceFieldAntialiasing(QSGGlyphNode::GrayAntialiasing)
+ #endif
, flashMode(qmlFlashMode())
, distanceFieldDisabled(qmlDisableDistanceField())
{
@@ -111,9 +118,11 @@ public:
QHash<QSGMaterialType *, QSGMaterialShader *> materials;
QMutex textureMutex;
QHash<QQuickTextureFactory *, QSGTexture *> textures;
-
+ QSGDepthStencilBufferManager *depthStencilBufferManager;
QSGDistanceFieldGlyphCacheManager *distanceFieldCacheManager;
+ QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing;
+
bool flashMode;
float renderAlpha;
bool distanceFieldDisabled;
@@ -141,6 +150,17 @@ public:
QSGContext::QSGContext(QObject *parent) :
QObject(*(new QSGContextPrivate), parent)
{
+ Q_D(QSGContext);
+ // ### Do something with these before final release...
+ static bool doSubpixel = qApp->arguments().contains(QLatin1String("--text-subpixel-antialiasing"));
+ static bool doLowQualSubpixel = qApp->arguments().contains(QLatin1String("--text-subpixel-antialiasing-lowq"));
+ static bool doGray = qApp->arguments().contains(QLatin1String("--text-gray-antialiasing"));
+ if (doSubpixel)
+ d->distanceFieldAntialiasing = QSGGlyphNode::HighQualitySubPixelAntialiasing;
+ else if (doLowQualSubpixel)
+ d->distanceFieldAntialiasing = QSGGlyphNode::LowQualitySubPixelAntialiasing;
+ else if (doGray)
+ d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing;
}
@@ -160,6 +180,8 @@ void QSGContext::invalidate()
d->textureMutex.unlock();
qDeleteAll(d->materials.values());
d->materials.clear();
+ delete d->depthStencilBufferManager;
+ d->depthStencilBufferManager = 0;
delete d->distanceFieldCacheManager;
d->distanceFieldCacheManager = 0;
@@ -270,39 +292,47 @@ QSGImageNode *QSGContext::createImageNode()
/*!
Factory function for scene graph backends of the distance-field glyph cache.
*/
-QSGDistanceFieldGlyphCache *QSGContext::createDistanceFieldGlyphCache(const QRawFont &font)
+QSGDistanceFieldGlyphCache *QSGContext::distanceFieldGlyphCache(const QRawFont &font)
{
Q_D(QSGContext);
- QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
- if (platformIntegration != 0
- && platformIntegration->hasCapability(QPlatformIntegration::SharedGraphicsCache)) {
- QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine;
- if (!fe->faceId().filename.isEmpty()) {
- QByteArray keyName = fe->faceId().filename;
- if (font.style() != QFont::StyleNormal)
- keyName += QByteArray(" I");
- if (font.weight() != QFont::Normal)
- keyName += " " + QByteArray::number(font.weight());
- keyName += QByteArray(" DF");
- QPlatformSharedGraphicsCache *sharedGraphicsCache =
- platformIntegration->createPlatformSharedGraphicsCache(keyName);
-
- if (sharedGraphicsCache != 0) {
- sharedGraphicsCache->ensureCacheInitialized(keyName,
- QPlatformSharedGraphicsCache::OpenGLTexture,
- QPlatformSharedGraphicsCache::Alpha8);
-
- return new QSGSharedDistanceFieldGlyphCache(keyName,
- sharedGraphicsCache,
- d->distanceFieldCacheManager,
- glContext(),
- font);
+ if (!d->distanceFieldCacheManager)
+ d->distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager;
+
+ QSGDistanceFieldGlyphCache *cache = d->distanceFieldCacheManager->cache(font);
+ if (!cache) {
+ QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ if (platformIntegration != 0
+ && platformIntegration->hasCapability(QPlatformIntegration::SharedGraphicsCache)) {
+ QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine;
+ if (!fe->faceId().filename.isEmpty()) {
+ QByteArray keyName = fe->faceId().filename;
+ if (font.style() != QFont::StyleNormal)
+ keyName += QByteArray(" I");
+ if (font.weight() != QFont::Normal)
+ keyName += " " + QByteArray::number(font.weight());
+ keyName += QByteArray(" DF");
+ QPlatformSharedGraphicsCache *sharedGraphicsCache =
+ platformIntegration->createPlatformSharedGraphicsCache(keyName);
+
+ if (sharedGraphicsCache != 0) {
+ sharedGraphicsCache->ensureCacheInitialized(keyName,
+ QPlatformSharedGraphicsCache::OpenGLTexture,
+ QPlatformSharedGraphicsCache::Alpha8);
+
+ cache = new QSGSharedDistanceFieldGlyphCache(keyName,
+ sharedGraphicsCache,
+ d->distanceFieldCacheManager,
+ glContext(),
+ font);
+ }
}
}
+ if (!cache)
+ cache = new QSGDefaultDistanceFieldGlyphCache(d->distanceFieldCacheManager, glContext(), font);
+ d->distanceFieldCacheManager->insertCache(font, cache);
}
-
- return new QSGDefaultDistanceFieldGlyphCache(d->distanceFieldCacheManager, glContext(), font);
+ return cache;
}
/*!
@@ -312,25 +342,11 @@ QSGGlyphNode *QSGContext::createGlyphNode()
{
Q_D(QSGContext);
- // ### Do something with these before final release...
- static bool doSubpixel = qApp->arguments().contains(QLatin1String("--text-subpixel-antialiasing"));
- static bool doLowQualSubpixel = qApp->arguments().contains(QLatin1String("--text-subpixel-antialiasing-lowq"));
- static bool doGray = qApp->arguments().contains(QLatin1String("--text-gray-antialiasing"));
-
if (d->distanceFieldDisabled) {
return new QSGDefaultGlyphNode;
} else {
- if (!d->distanceFieldCacheManager) {
- d->distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager(this);
- if (doSubpixel)
- d->distanceFieldCacheManager->setDefaultAntialiasingMode(QSGGlyphNode::HighQualitySubPixelAntialiasing);
- else if (doLowQualSubpixel)
- d->distanceFieldCacheManager->setDefaultAntialiasingMode(QSGGlyphNode::LowQualitySubPixelAntialiasing);
- else if (doGray)
- d->distanceFieldCacheManager->setDefaultAntialiasingMode(QSGGlyphNode::GrayAntialiasing);
- }
-
- QSGGlyphNode *node = new QSGDistanceFieldGlyphNode(d->distanceFieldCacheManager);
+ QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(this);
+ node->setPreferredAntialiasingMode(d->distanceFieldAntialiasing);
return node;
}
}
@@ -399,6 +415,42 @@ QSize QSGContext::minimumFBOSize() const
/*!
+ Returns a shared pointer to a depth stencil buffer that can be used with \a fbo.
+ */
+QSharedPointer<QSGDepthStencilBuffer> QSGContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo)
+{
+ Q_D(QSGContext);
+ if (!d->gl)
+ return QSharedPointer<QSGDepthStencilBuffer>();
+ QSGDepthStencilBufferManager *manager = depthStencilBufferManager();
+ QSGDepthStencilBuffer::Format format;
+ format.size = fbo->size();
+ format.samples = fbo->format().samples();
+ format.attachments = QSGDepthStencilBuffer::DepthAttachment | QSGDepthStencilBuffer::StencilAttachment;
+ QSharedPointer<QSGDepthStencilBuffer> buffer = manager->bufferForFormat(format);
+ if (buffer.isNull()) {
+ buffer = QSharedPointer<QSGDepthStencilBuffer>(new QSGDefaultDepthStencilBuffer(d->gl, format));
+ manager->insertBuffer(buffer);
+ }
+ return buffer;
+}
+
+/*!
+ Returns a pointer to the context's depth/stencil buffer manager. This is useful for custom
+ implementations of \l depthStencilBufferForFbo().
+ */
+QSGDepthStencilBufferManager *QSGContext::depthStencilBufferManager()
+{
+ Q_D(QSGContext);
+ if (!d->gl)
+ return 0;
+ if (!d->depthStencilBufferManager)
+ d->depthStencilBufferManager = new QSGDepthStencilBufferManager(d->gl);
+ return d->depthStencilBufferManager;
+}
+
+
+/*!
Returns a material shader for the given material.
*/
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index dfb960f420..7cbff40a9b 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -51,6 +51,7 @@
#include <private/qrawfont_p.h>
#include <QtQuick/qsgnode.h>
+#include <QtQuick/private/qsgdepthstencilbuffer_p.h>
QT_BEGIN_HEADER
@@ -95,7 +96,7 @@ public:
virtual void renderNextFrame(QSGRenderer *renderer, GLuint fboId);
- virtual QSGDistanceFieldGlyphCache *createDistanceFieldGlyphCache(const QRawFont &font);
+ virtual QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font);
virtual QSGRectangleNode *createRectangleNode();
virtual QSGImageNode *createImageNode();
@@ -104,6 +105,8 @@ public:
virtual QSGTexture *createTexture(const QImage &image = QImage()) const;
virtual QSize minimumFBOSize() const;
+ virtual QSharedPointer<QSGDepthStencilBuffer> depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo);
+ QSGDepthStencilBufferManager *depthStencilBufferManager();
virtual QSurfaceFormat defaultSurfaceFormat() const;
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index 5864f35060..2b2ccfe317 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -47,24 +47,41 @@
QT_BEGIN_NAMESPACE
-QHash<QString, QOpenGLMultiGroupSharedResource> QSGDefaultDistanceFieldGlyphCache::m_textures_data;
-
-QSGDefaultDistanceFieldGlyphCache::DistanceFieldTextureData *QSGDefaultDistanceFieldGlyphCache::textureData(QOpenGLContext *c)
-{
- QString key = QString::fromLatin1("%1_%2_%3_%4")
- .arg(font().familyName())
- .arg(font().styleName())
- .arg(font().weight())
- .arg(font().style());
- return m_textures_data[key].value<QSGDefaultDistanceFieldGlyphCache::DistanceFieldTextureData>(c);
-}
QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font)
: QSGDistanceFieldGlyphCache(man, c, font)
, m_maxTextureSize(0)
, m_maxTextureCount(3)
+ , m_fbo(0)
+ , m_blitProgram(0)
+{
+ m_currentTexture = createTextureInfo();
+
+ m_blitVertexCoordinateArray[0] = -1.0f;
+ m_blitVertexCoordinateArray[1] = -1.0f;
+ m_blitVertexCoordinateArray[2] = 1.0f;
+ m_blitVertexCoordinateArray[3] = -1.0f;
+ m_blitVertexCoordinateArray[4] = 1.0f;
+ m_blitVertexCoordinateArray[5] = 1.0f;
+ m_blitVertexCoordinateArray[6] = -1.0f;
+ m_blitVertexCoordinateArray[7] = 1.0f;
+
+ m_blitTextureCoordinateArray[0] = 0.0f;
+ m_blitTextureCoordinateArray[1] = 0.0f;
+ m_blitTextureCoordinateArray[2] = 1.0f;
+ m_blitTextureCoordinateArray[3] = 0.0f;
+ m_blitTextureCoordinateArray[4] = 1.0f;
+ m_blitTextureCoordinateArray[5] = 1.0f;
+ m_blitTextureCoordinateArray[6] = 0.0f;
+ m_blitTextureCoordinateArray[7] = 1.0f;
+}
+
+QSGDefaultDistanceFieldGlyphCache::~QSGDefaultDistanceFieldGlyphCache()
{
- m_textureData = textureData(c);
+ for (int i = 0; i < m_textures.count(); ++i)
+ glDeleteTextures(1, &m_textures[i].texture);
+ ctx->functions()->glDeleteFramebuffers(1, &m_fbo);
+ delete m_blitProgram;
}
void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs)
@@ -75,15 +92,15 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph
for (QSet<glyph_t>::const_iterator it = glyphs.constBegin(); it != glyphs.constEnd() ; ++it) {
glyph_t glyphIndex = *it;
- if (cacheIsFull() && m_textureData->unusedGlyphs.isEmpty())
+ if (cacheIsFull() && m_unusedGlyphs.isEmpty())
continue;
- if (textureIsFull(m_textureData->currentTexture) && m_textureData->textures.count() < m_maxTextureCount)
- m_textureData->currentTexture = m_textureData->addTexture();
+ if (textureIsFull(m_currentTexture) && m_textures.count() < m_maxTextureCount)
+ m_currentTexture = createTextureInfo();
- m_textureData->unusedGlyphs.remove(glyphIndex);
+ m_unusedGlyphs.remove(glyphIndex);
- DistanceFieldTextureData::TextureInfo *tex = m_textureData->currentTexture;
+ TextureInfo *tex = m_currentTexture;
GlyphPosition p;
p.glyph = glyphIndex;
@@ -97,13 +114,13 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph
}
} else {
// Recycle glyphs
- if (!m_textureData->unusedGlyphs.isEmpty()) {
- glyph_t unusedGlyph = *m_textureData->unusedGlyphs.constBegin();
+ if (!m_unusedGlyphs.isEmpty()) {
+ glyph_t unusedGlyph = *m_unusedGlyphs.constBegin();
TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
- tex = m_textureData->glyphsTexture.value(unusedGlyph);
+ tex = m_glyphsTexture.value(unusedGlyph);
p.position = QPointF(unusedCoord.x, unusedCoord.y);
- m_textureData->unusedGlyphs.remove(unusedGlyph);
- m_textureData->glyphsTexture.remove(unusedGlyph);
+ m_unusedGlyphs.remove(unusedGlyph);
+ m_glyphsTexture.remove(unusedGlyph);
removeGlyph(unusedGlyph);
}
}
@@ -111,7 +128,7 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph
if (p.position.y() < maxTextureSize()) {
glyphPositions.append(p);
glyphsToRender.append(glyphIndex);
- m_textureData->glyphsTexture.insert(glyphIndex, tex);
+ m_glyphsTexture.insert(glyphIndex, tex);
}
}
@@ -124,13 +141,13 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage>
int requiredWidth = maxTextureSize();
int rows = 128 / (requiredWidth / QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution())); // Enough rows to fill the latin1 set by default..
- QHash<DistanceFieldTextureData::TextureInfo *, QVector<glyph_t> > glyphTextures;
+ QHash<TextureInfo *, QVector<glyph_t> > glyphTextures;
QHash<glyph_t, QImage>::const_iterator it;
for (it = glyphs.constBegin(); it != glyphs.constEnd(); ++it) {
glyph_t glyphIndex = it.key();
TexCoord c = glyphTexCoord(glyphIndex);
- DistanceFieldTextureData::TextureInfo *texInfo = m_textureData->glyphsTexture.value(glyphIndex);
+ TextureInfo *texInfo = m_glyphsTexture.value(glyphIndex);
int requiredHeight = qMin(maxTextureSize(),
qMax(texInfo->currY + QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()),
@@ -156,7 +173,7 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage>
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
}
- QHash<DistanceFieldTextureData::TextureInfo *, QVector<glyph_t> >::const_iterator i;
+ QHash<TextureInfo *, QVector<glyph_t> >::const_iterator i;
for (i = glyphTextures.constBegin(); i != glyphTextures.constEnd(); ++i) {
Texture t;
t.textureId = i.key()->texture;
@@ -167,15 +184,15 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage>
void QSGDefaultDistanceFieldGlyphCache::referenceGlyphs(const QSet<glyph_t> &glyphs)
{
- m_textureData->unusedGlyphs -= glyphs;
+ m_unusedGlyphs -= glyphs;
}
void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyphs)
{
- m_textureData->unusedGlyphs += glyphs;
+ m_unusedGlyphs += glyphs;
}
-void QSGDefaultDistanceFieldGlyphCache::createTexture(DistanceFieldTextureData::TextureInfo *texInfo, int width, int height)
+void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int width, int height)
{
if (useWorkaroundBrokenFBOReadback() && texInfo->image.isNull())
texInfo->image = QImage(width, height, QImage::Format_Indexed8);
@@ -202,7 +219,7 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(DistanceFieldTextureData::
}
-void QSGDefaultDistanceFieldGlyphCache::resizeTexture(DistanceFieldTextureData::TextureInfo *texInfo, int width, int height)
+void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int width, int height)
{
int oldWidth = texInfo->size.width();
int oldHeight = texInfo->size.height();
@@ -224,14 +241,14 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(DistanceFieldTextureData::
return;
}
- if (!m_textureData->blitProgram)
- m_textureData->createBlitProgram();
+ if (!m_blitProgram)
+ createBlitProgram();
- Q_ASSERT(m_textureData->blitProgram);
+ Q_ASSERT(m_blitProgram);
- if (!m_textureData->fbo)
- ctx->functions()->glGenFramebuffers(1, &m_textureData->fbo);
- ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_textureData->fbo);
+ if (!m_fbo)
+ ctx->functions()->glGenFramebuffers(1, &m_fbo);
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
GLuint tmp_texture;
glGenTextures(1, &tmp_texture);
@@ -270,14 +287,14 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(DistanceFieldTextureData::
glViewport(0, 0, oldWidth, oldHeight);
- ctx->functions()->glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_textureData->blitVertexCoordinateArray);
- ctx->functions()->glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_textureData->blitTextureCoordinateArray);
+ ctx->functions()->glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_blitVertexCoordinateArray);
+ ctx->functions()->glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_blitTextureCoordinateArray);
- m_textureData->blitProgram->bind();
- m_textureData->blitProgram->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
- m_textureData->blitProgram->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
- m_textureData->blitProgram->disableAttributeArray(int(QT_OPACITY_ATTR));
- m_textureData->blitProgram->setUniformValue("imageTexture", GLuint(0));
+ m_blitProgram->bind();
+ m_blitProgram->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
+ m_blitProgram->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
+ m_blitProgram->disableAttributeArray(int(QT_OPACITY_ATTR));
+ m_blitProgram->setUniformValue("imageTexture", GLuint(0));
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -304,8 +321,8 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(DistanceFieldTextureData::
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
ctx->functions()->glUseProgram(oldProgram);
- m_textureData->blitProgram->disableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
- m_textureData->blitProgram->disableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
+ m_blitProgram->disableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
+ m_blitProgram->disableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
}
bool QSGDefaultDistanceFieldGlyphCache::useWorkaroundBrokenFBOReadback() const
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
index 12bbcce060..38cc649b3a 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
@@ -53,6 +53,7 @@ class Q_QUICK_EXPORT QSGDefaultDistanceFieldGlyphCache : public QSGDistanceField
{
public:
QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font);
+ virtual ~QSGDefaultDistanceFieldGlyphCache();
void requestGlyphs(const QSet<glyph_t> &glyphs);
void storeGlyphs(const QHash<glyph_t, QImage> &glyphs);
@@ -60,8 +61,8 @@ public:
void releaseGlyphs(const QSet<glyph_t> &glyphs);
bool cacheIsFull() const {
- return m_textureData->textures.count() == m_maxTextureCount
- && textureIsFull(m_textureData->currentTexture);
+ return m_textures.count() == m_maxTextureCount
+ && textureIsFull(m_currentTexture);
}
bool useWorkaroundBrokenFBOReadback() const;
int maxTextureSize() const;
@@ -70,123 +71,67 @@ public:
int maxTextureCount() const { return m_maxTextureCount; }
private:
- mutable int m_maxTextureSize;
- int m_maxTextureCount;
+ struct TextureInfo {
+ GLuint texture;
+ QSize size;
+ int currX;
+ int currY;
+ QImage image;
+
+ TextureInfo() : texture(0), currX(0), currY(0)
+ { }
+ };
- struct DistanceFieldTextureData : public QOpenGLSharedResource {
- struct TextureInfo {
- GLuint texture;
- QSize size;
- int currX;
- int currY;
- QImage image;
-
- TextureInfo() : texture(0), currX(0), currY(0)
- { }
- };
-
- TextureInfo *currentTexture;
- QList<TextureInfo> textures;
- QHash<glyph_t, TextureInfo *> glyphsTexture;
- GLuint fbo;
- QSet<glyph_t> unusedGlyphs;
-
- QOpenGLShaderProgram *blitProgram;
- GLfloat blitVertexCoordinateArray[8];
- GLfloat blitTextureCoordinateArray[8];
-
- TextureInfo *addTexture()
- {
- textures.append(TextureInfo());
- return &textures.last();
- }
+ void createTexture(TextureInfo * texInfo, int width, int height);
+ void resizeTexture(TextureInfo * texInfo, int width, int height);
+ bool textureIsFull (const TextureInfo *tex) const { return tex->currY >= maxTextureSize(); }
- DistanceFieldTextureData(QOpenGLContext *ctx)
- : QOpenGLSharedResource(ctx->shareGroup())
- , fbo(0)
- , blitProgram(0)
- {
- currentTexture = addTexture();
-
- blitVertexCoordinateArray[0] = -1.0f;
- blitVertexCoordinateArray[1] = -1.0f;
- blitVertexCoordinateArray[2] = 1.0f;
- blitVertexCoordinateArray[3] = -1.0f;
- blitVertexCoordinateArray[4] = 1.0f;
- blitVertexCoordinateArray[5] = 1.0f;
- blitVertexCoordinateArray[6] = -1.0f;
- blitVertexCoordinateArray[7] = 1.0f;
-
- blitTextureCoordinateArray[0] = 0.0f;
- blitTextureCoordinateArray[1] = 0.0f;
- blitTextureCoordinateArray[2] = 1.0f;
- blitTextureCoordinateArray[3] = 0.0f;
- blitTextureCoordinateArray[4] = 1.0f;
- blitTextureCoordinateArray[5] = 1.0f;
- blitTextureCoordinateArray[6] = 0.0f;
- blitTextureCoordinateArray[7] = 1.0f;
- }
+ TextureInfo *createTextureInfo()
+ {
+ m_textures.append(TextureInfo());
+ return &m_textures.last();
+ }
- void invalidateResource()
+ void createBlitProgram()
+ {
+ m_blitProgram = new QOpenGLShaderProgram;
{
- glyphsTexture.clear();
- textures.clear();
- fbo = 0;
- delete blitProgram;
- blitProgram = 0;
+ QString source;
+ source.append(QLatin1String(qopenglslMainWithTexCoordsVertexShader));
+ source.append(QLatin1String(qopenglslUntransformedPositionVertexShader));
- currentTexture = addTexture();
- }
+ QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_blitProgram);
+ vertexShader->compileSourceCode(source);
- void freeResource(QOpenGLContext *ctx)
- {
- glyphsTexture.clear();
- for (int i = 0; i < textures.count(); ++i)
- glDeleteTextures(1, &textures[i].texture);
- textures.clear();
- ctx->functions()->glDeleteFramebuffers(1, &fbo);
- delete blitProgram;
- blitProgram = 0;
-
- currentTexture = addTexture();
+ m_blitProgram->addShader(vertexShader);
}
-
- void createBlitProgram()
{
- blitProgram = new QOpenGLShaderProgram;
- {
- QString source;
- source.append(QLatin1String(qopenglslMainWithTexCoordsVertexShader));
- source.append(QLatin1String(qopenglslUntransformedPositionVertexShader));
-
- QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, blitProgram);
- vertexShader->compileSourceCode(source);
-
- blitProgram->addShader(vertexShader);
- }
- {
- QString source;
- source.append(QLatin1String(qopenglslMainFragmentShader));
- source.append(QLatin1String(qopenglslImageSrcFragmentShader));
-
- QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, blitProgram);
- fragmentShader->compileSourceCode(source);
-
- blitProgram->addShader(fragmentShader);
- }
- blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
- blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
- blitProgram->link();
+ QString source;
+ source.append(QLatin1String(qopenglslMainFragmentShader));
+ source.append(QLatin1String(qopenglslImageSrcFragmentShader));
+
+ QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_blitProgram);
+ fragmentShader->compileSourceCode(source);
+
+ m_blitProgram->addShader(fragmentShader);
}
- };
+ m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+ m_blitProgram->link();
+ }
+
+ mutable int m_maxTextureSize;
+ int m_maxTextureCount;
- void createTexture(DistanceFieldTextureData::TextureInfo * texInfo, int width, int height);
- void resizeTexture(DistanceFieldTextureData::TextureInfo * texInfo, int width, int height);
- bool textureIsFull (const DistanceFieldTextureData::TextureInfo *tex) const { return tex->currY >= maxTextureSize(); }
+ TextureInfo *m_currentTexture;
+ QList<TextureInfo> m_textures;
+ QHash<glyph_t, TextureInfo *> m_glyphsTexture;
+ GLuint m_fbo;
+ QSet<glyph_t> m_unusedGlyphs;
- DistanceFieldTextureData *textureData(QOpenGLContext *c);
- DistanceFieldTextureData *m_textureData;
- static QHash<QString, QOpenGLMultiGroupSharedResource> m_textures_data;
+ QOpenGLShaderProgram *m_blitProgram;
+ GLfloat m_blitVertexCoordinateArray[8];
+ GLfloat m_blitTextureCoordinateArray[8];
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
index a86e663755..d6fe6f938c 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
@@ -46,9 +46,10 @@
QT_BEGIN_NAMESPACE
-QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGDistanceFieldGlyphCacheManager *cacheManager)
- : m_material(0)
- , m_glyph_cacheManager(cacheManager)
+QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGContext *context)
+ : m_glyphNodeType(RootGlyphNode)
+ , m_context(context)
+ , m_material(0)
, m_glyph_cache(0)
, m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
, m_style(QQuickText::Normal)
@@ -59,7 +60,6 @@ QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGDistanceFieldGlyphCacheM
{
m_geometry.setDrawingMode(GL_TRIANGLES);
setGeometry(&m_geometry);
- setPreferredAntialiasingMode(cacheManager->defaultAntialiasingMode());
setFlag(UsePreprocess);
#ifdef QML_RUNTIME_TESTING
description = QLatin1String("glyphs");
@@ -70,15 +70,17 @@ QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode()
{
delete m_material;
+ if (m_glyphNodeType == SubGlyphNode)
+ return;
+
if (m_glyph_cache) {
m_glyph_cache->release(m_glyphs.glyphIndexes());
m_glyph_cache->unregisterGlyphNode(this);
m_glyph_cache->unregisterOwnerElement(ownerElement());
}
- for (int i = 0; i < m_nodesToDelete.count(); ++i)
- delete m_nodesToDelete.at(i);
- m_nodesToDelete.clear();
+ while (m_nodesToDelete.count())
+ delete m_nodesToDelete.takeLast();
}
void QSGDistanceFieldGlyphNode::setColor(const QColor &color)
@@ -107,8 +109,15 @@ void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphR
m_position = QPointF(position.x(), position.y() - font.ascent());
m_glyphs = glyphs;
+ m_dirtyGeometry = true;
+ m_dirtyMaterial = true;
+
QSGDistanceFieldGlyphCache *oldCache = m_glyph_cache;
- m_glyph_cache = m_glyph_cacheManager->cache(m_glyphs.rawFont());
+ m_glyph_cache = m_context->distanceFieldGlyphCache(m_glyphs.rawFont());
+
+ if (m_glyphNodeType == SubGlyphNode)
+ return;
+
if (m_glyph_cache != oldCache) {
Q_ASSERT(ownerElement() != 0);
if (oldCache) {
@@ -123,9 +132,6 @@ void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphR
const QVector<quint32> glyphIndexes = m_glyphs.glyphIndexes();
for (int i = 0; i < glyphIndexes.count(); ++i)
m_allGlyphIndexesLookup.insert(glyphIndexes.at(i));
-
- m_dirtyGeometry = true;
- m_dirtyMaterial = true;
}
void QSGDistanceFieldGlyphNode::setStyle(QQuickText::TextStyle style)
@@ -154,9 +160,8 @@ void QSGDistanceFieldGlyphNode::preprocess()
{
Q_ASSERT(m_glyph_cache);
- for (int i = 0; i < m_nodesToDelete.count(); ++i)
- delete m_nodesToDelete.at(i);
- m_nodesToDelete.clear();
+ while (m_nodesToDelete.count())
+ delete m_nodesToDelete.takeLast();
m_glyph_cache->processPendingGlyphs();
m_glyph_cache->update();
@@ -183,14 +188,15 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
Q_ASSERT(m_glyph_cache);
// Remove previously created sub glyph nodes
- QHash<const QSGDistanceFieldGlyphCache::Texture *, QSGDistanceFieldGlyphNode *>::iterator it = m_subNodes.begin();
- while (it != m_subNodes.end()) {
- removeChildNode(it.value());
+ // We assume all the children are sub glyph nodes
+ QSGNode *subnode = firstChild();
+ while (subnode) {
// We can't delete the node now as it might be in the preprocess list
// It will be deleted in the next preprocess
- m_nodesToDelete.append(it.value());
- it = m_subNodes.erase(it);
+ m_nodesToDelete.append(subnode);
+ subnode = subnode->nextSibling();
}
+ removeAllChildNodes();
QSGGeometry *g = geometry();
@@ -200,6 +206,7 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
const QVector<quint32> indexes = m_glyphs.glyphIndexes();
const QVector<QPointF> positions = m_glyphs.positions();
+ qreal fontPixelSize = m_glyphs.rawFont().pixelSize();
QVector<QSGGeometry::TexturedPoint2D> vp;
vp.reserve(indexes.size() * 4);
@@ -207,8 +214,7 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
ip.reserve(indexes.size() * 6);
QPointF margins(2, 2);
- QPointF texMargins = margins / m_glyph_cache->fontScale();
-
+ QPointF texMargins = margins / m_glyph_cache->fontScale(fontPixelSize);
for (int i = 0; i < indexes.size(); ++i) {
const int glyphIndex = indexes.at(i);
@@ -232,7 +238,7 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
continue;
}
- QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex);
+ QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex, fontPixelSize);
if (!metrics.isNull() && !c.isNull()) {
metrics.width += margins.x() * 2;
@@ -288,25 +294,19 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
QHash<const QSGDistanceFieldGlyphCache::Texture *, GlyphInfo>::const_iterator ite = glyphsInOtherTextures.constBegin();
while (ite != glyphsInOtherTextures.constEnd()) {
- QHash<const QSGDistanceFieldGlyphCache::Texture *, QSGDistanceFieldGlyphNode *>::iterator subIt = m_subNodes.find(ite.key());
- if (subIt == m_subNodes.end()) {
- QSGDistanceFieldGlyphNode *subNode = new QSGDistanceFieldGlyphNode(m_glyph_cacheManager);
- subNode->setOwnerElement(m_ownerElement);
- subNode->setColor(m_color);
- subNode->setStyle(m_style);
- subNode->setStyleColor(m_styleColor);
- subNode->update();
- appendChildNode(subNode);
- subIt = m_subNodes.insert(ite.key(), subNode);
- }
-
QGlyphRun subNodeGlyphRun(m_glyphs);
subNodeGlyphRun.setGlyphIndexes(ite->indexes);
subNodeGlyphRun.setPositions(ite->positions);
- subIt.value()->setGlyphs(m_originalPosition, subNodeGlyphRun);
- subIt.value()->update();
- subIt.value()->updateGeometry(); // we have to explicity call this now as preprocess won't be called before it's rendered
+ QSGDistanceFieldGlyphNode *subNode = new QSGDistanceFieldGlyphNode(m_context);
+ subNode->setGlyphNodeType(SubGlyphNode);
+ subNode->setColor(m_color);
+ subNode->setStyle(m_style);
+ subNode->setStyleColor(m_styleColor);
+ subNode->setGlyphs(m_originalPosition, subNodeGlyphRun);
+ subNode->update();
+ subNode->updateGeometry(); // we have to explicity call this now as preprocess won't be called before it's rendered
+ appendChildNode(subNode);
++ite;
}
@@ -356,6 +356,8 @@ void QSGDistanceFieldGlyphNode::updateMaterial()
}
m_material->setGlyphCache(m_glyph_cache);
+ if (m_glyph_cache)
+ m_material->setFontScale(m_glyph_cache->fontScale(m_glyphs.rawFont().pixelSize()));
m_material->setColor(m_color);
setMaterial(m_material);
m_dirtyMaterial = false;
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
index c66b82c16e..cd988c70d7 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -151,8 +151,8 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q
bool updateRange = false;
if (oldMaterial == 0
- || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale()) {
- m_fontScale = material->glyphCache()->fontScale();
+ || material->fontScale() != oldMaterial->fontScale()) {
+ m_fontScale = material->fontScale();
updateRange = true;
}
if (state.isMatrixDirty()) {
@@ -226,10 +226,8 @@ int QSGDistanceFieldTextMaterial::compare(const QSGMaterial *o) const
const QSGDistanceFieldTextMaterial *other = static_cast<const QSGDistanceFieldTextMaterial *>(o);
if (m_glyph_cache != other->m_glyph_cache)
return m_glyph_cache - other->m_glyph_cache;
- if (m_glyph_cache->fontScale() != other->m_glyph_cache->fontScale()) {
- qreal s1 = m_glyph_cache->fontScale();
- qreal s2 = other->m_glyph_cache->fontScale();
- return int(s2 < s1) - int(s1 < s2);
+ if (m_fontScale != other->m_fontScale) {
+ return int(other->m_fontScale < m_fontScale) - int(m_fontScale < other->m_fontScale);
}
QRgb c1 = m_color.rgba();
QRgb c2 = other->m_color.rgba();
@@ -371,7 +369,7 @@ void DistanceFieldOutlineTextMaterialShader::updateState(const RenderState &stat
QSGDistanceFieldOutlineTextMaterial *oldMaterial = static_cast<QSGDistanceFieldOutlineTextMaterial *>(oldEffect);
if (oldMaterial == 0
- || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale()
+ || material->fontScale() != oldMaterial->fontScale()
|| state.isMatrixDirty())
updateOutlineAlphaRange(material->glyphCache()->distanceFieldRadius());
}
@@ -410,7 +408,7 @@ protected:
virtual const char *vertexShader() const;
virtual const char *fragmentShader() const;
- void updateShift(const QSGDistanceFieldGlyphCache *cache, const QPointF& shift);
+ void updateShift(qreal fontScale, const QPointF& shift);
int m_shift_id;
};
@@ -434,17 +432,17 @@ void DistanceFieldShiftedStyleTextMaterialShader::updateState(const RenderState
QSGDistanceFieldShiftedStyleTextMaterial *oldMaterial = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(oldEffect);
if (oldMaterial == 0
- || oldMaterial->glyphCache()->fontScale() != material->glyphCache()->fontScale()
+ || oldMaterial->fontScale() != material->fontScale()
|| oldMaterial->shift() != material->shift()
|| oldMaterial->textureSize() != material->textureSize()) {
- updateShift(material->glyphCache(), material->shift());
+ updateShift(material->fontScale(), material->shift());
}
}
-void DistanceFieldShiftedStyleTextMaterialShader::updateShift(const QSGDistanceFieldGlyphCache *cache, const QPointF &shift)
+void DistanceFieldShiftedStyleTextMaterialShader::updateShift(qreal fontScale, const QPointF &shift)
{
- QPointF texel(1.0 / cache->fontScale() * shift.x(),
- 1.0 / cache->fontScale() * shift.y());
+ QPointF texel(1.0 / fontScale * shift.x(),
+ 1.0 / fontScale * shift.y());
program()->setUniformValue(m_shift_id, texel);
}
@@ -639,8 +637,8 @@ void QSGHiQSubPixelDistanceFieldTextMaterialShader::updateState(const RenderStat
state.context()->functions()->glBlendColor(c.redF(), c.greenF(), c.blueF(), 1.0f);
}
- if (oldMaterial == 0 || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale())
- program()->setUniformValue(m_fontScale_id, GLfloat(material->glyphCache()->fontScale()));
+ if (oldMaterial == 0 || material->fontScale() != oldMaterial->fontScale())
+ program()->setUniformValue(m_fontScale_id, GLfloat(material->fontScale()));
if (oldMaterial == 0 || state.isMatrixDirty()) {
int viewportWidth = state.viewportRect().width();
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
index 9406ee1bc8..146267c45d 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
@@ -51,12 +51,13 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
+class QSGContext;
class QSGDistanceFieldGlyphCacheManager;
class QSGDistanceFieldTextMaterial;
-class QSGDistanceFieldGlyphNode: public QSGGlyphNode
+class QSGDistanceFieldGlyphNode: public QSGGlyphNode, public QSGDistanceFieldGlyphConsumer
{
public:
- QSGDistanceFieldGlyphNode(QSGDistanceFieldGlyphCacheManager *cacheManager);
+ QSGDistanceFieldGlyphNode(QSGContext *context);
~QSGDistanceFieldGlyphNode();
virtual QPointF baseLine() const { return m_baseLine; }
@@ -76,15 +77,22 @@ public:
void updateGeometry();
private:
+ enum DistanceFieldGlyphNodeType {
+ RootGlyphNode,
+ SubGlyphNode
+ };
+
+ void setGlyphNodeType(DistanceFieldGlyphNodeType type) { m_glyphNodeType = type; }
void updateMaterial();
+ DistanceFieldGlyphNodeType m_glyphNodeType;
QColor m_color;
QPointF m_baseLine;
+ QSGContext *m_context;
QSGDistanceFieldTextMaterial *m_material;
QPointF m_originalPosition;
QPointF m_position;
QGlyphRun m_glyphs;
- QSGDistanceFieldGlyphCacheManager *m_glyph_cacheManager;
QSGDistanceFieldGlyphCache *m_glyph_cache;
QSGGeometry m_geometry;
QQuickText::TextStyle m_style;
@@ -92,8 +100,7 @@ private:
AntialiasingMode m_antialiasingMode;
QRectF m_boundingRect;
const QSGDistanceFieldGlyphCache::Texture *m_texture;
- QHash<const QSGDistanceFieldGlyphCache::Texture *, QSGDistanceFieldGlyphNode *> m_subNodes;
- QList<QSGDistanceFieldGlyphNode *> m_nodesToDelete;
+ QLinkedList<QSGNode *> m_nodesToDelete;
struct GlyphInfo {
QVector<quint32> indexes;
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
index c4af15a2af..8b2654e078 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
@@ -48,7 +48,7 @@
QT_BEGIN_NAMESPACE
-class QSGDistanceFieldTextMaterial: public QSGMaterial
+class Q_QUICK_EXPORT QSGDistanceFieldTextMaterial: public QSGMaterial
{
public:
QSGDistanceFieldTextMaterial();
@@ -67,6 +67,9 @@ public:
void setTexture(const QSGDistanceFieldGlyphCache::Texture * tex) { m_texture = tex; }
const QSGDistanceFieldGlyphCache::Texture * texture() const { return m_texture; }
+ void setFontScale(qreal fontScale) { m_fontScale = fontScale; }
+ qreal fontScale() const { return m_fontScale; }
+
QSize textureSize() const { return m_size; }
bool updateTextureSize();
@@ -76,9 +79,10 @@ protected:
QColor m_color;
QSGDistanceFieldGlyphCache *m_glyph_cache;
const QSGDistanceFieldGlyphCache::Texture *m_texture;
+ qreal m_fontScale;
};
-class QSGDistanceFieldStyledTextMaterial : public QSGDistanceFieldTextMaterial
+class Q_QUICK_EXPORT QSGDistanceFieldStyledTextMaterial : public QSGDistanceFieldTextMaterial
{
public:
QSGDistanceFieldStyledTextMaterial();
@@ -95,7 +99,7 @@ protected:
QColor m_styleColor;
};
-class QSGDistanceFieldOutlineTextMaterial : public QSGDistanceFieldStyledTextMaterial
+class Q_QUICK_EXPORT QSGDistanceFieldOutlineTextMaterial : public QSGDistanceFieldStyledTextMaterial
{
public:
QSGDistanceFieldOutlineTextMaterial();
@@ -105,7 +109,7 @@ public:
virtual QSGMaterialShader *createShader() const;
};
-class QSGDistanceFieldShiftedStyleTextMaterial : public QSGDistanceFieldStyledTextMaterial
+class Q_QUICK_EXPORT QSGDistanceFieldShiftedStyleTextMaterial : public QSGDistanceFieldStyledTextMaterial
{
public:
QSGDistanceFieldShiftedStyleTextMaterial();
@@ -121,14 +125,14 @@ protected:
QPointF m_shift;
};
-class QSGHiQSubPixelDistanceFieldTextMaterial : public QSGDistanceFieldTextMaterial
+class Q_QUICK_EXPORT QSGHiQSubPixelDistanceFieldTextMaterial : public QSGDistanceFieldTextMaterial
{
public:
virtual QSGMaterialType *type() const;
virtual QSGMaterialShader *createShader() const;
};
-class QSGLoQSubPixelDistanceFieldTextMaterial : public QSGDistanceFieldTextMaterial
+class Q_QUICK_EXPORT QSGLoQSubPixelDistanceFieldTextMaterial : public QSGDistanceFieldTextMaterial
{
public:
virtual QSGMaterialType *type() const;
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index f5fa18f87a..b6f7a228d2 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -23,6 +23,7 @@ SOURCES += \
# Util API
HEADERS += \
$$PWD/util/qsgareaallocator_p.h \
+ $$PWD/util/qsgdepthstencilbuffer_p.h \
$$PWD/util/qsgengine.h \
$$PWD/util/qsgflatcolormaterial.h \
$$PWD/util/qsgsimplematerial.h \
@@ -39,6 +40,7 @@ HEADERS += \
SOURCES += \
$$PWD/util/qsgareaallocator.cpp \
+ $$PWD/util/qsgdepthstencilbuffer.cpp \
$$PWD/util/qsgengine.cpp \
$$PWD/util/qsgflatcolormaterial.cpp \
$$PWD/util/qsgsimplerectnode.cpp \
diff --git a/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp
new file mode 100644
index 0000000000..bca57a3b6b
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdepthstencilbuffer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGDepthStencilBuffer::QSGDepthStencilBuffer(QOpenGLContext *context, const Format &format)
+ : m_functions(context)
+ , m_manager(0)
+ , m_format(format)
+ , m_depthBuffer(0)
+ , m_stencilBuffer(0)
+{
+ // 'm_manager' is set by QSGDepthStencilBufferManager::insertBuffer().
+}
+
+QSGDepthStencilBuffer::~QSGDepthStencilBuffer()
+{
+ if (m_manager)
+ m_manager->m_buffers.remove(m_format);
+}
+
+void QSGDepthStencilBuffer::attach()
+{
+ m_functions.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, m_depthBuffer);
+ m_functions.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, m_stencilBuffer);
+}
+
+void QSGDepthStencilBuffer::detach()
+{
+ m_functions.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, 0);
+ m_functions.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, 0);
+}
+
+
+QSGDefaultDepthStencilBuffer::QSGDefaultDepthStencilBuffer(QOpenGLContext *context, const Format &format)
+ : QSGDepthStencilBuffer(context, format)
+{
+ const GLsizei width = format.size.width();
+ const GLsizei height = format.size.height();
+
+ if (format.attachments == (DepthAttachment | StencilAttachment)
+ && m_functions.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil))
+ {
+ m_functions.glGenRenderbuffers(1, &m_depthBuffer);
+ m_functions.glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
+ if (format.samples && m_functions.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) {
+ m_functions.glRenderbufferStorageMultisample(GL_RENDERBUFFER, format.samples,
+ GL_DEPTH24_STENCIL8, width, height);
+ } else {
+ m_functions.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
+ }
+ m_stencilBuffer = m_depthBuffer;
+ }
+ if (!m_depthBuffer && (format.attachments & DepthAttachment)) {
+ m_functions.glGenRenderbuffers(1, &m_depthBuffer);
+ m_functions.glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
+#ifdef QT_OPENGL_ES
+ const GLenum internalFormat = m_functions.hasOpenGLExtension(QOpenGLExtensions::Depth24)
+ ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16;
+#else
+ const GLenum internalFormat = GL_DEPTH_COMPONENT;
+#endif
+ if (format.samples && m_functions.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) {
+ m_functions.glRenderbufferStorageMultisample(GL_RENDERBUFFER, format.samples,
+ internalFormat, width, height);
+ } else {
+ m_functions.glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, width, height);
+ }
+ }
+ if (!m_stencilBuffer && (format.attachments & StencilAttachment)) {
+ m_functions.glGenRenderbuffers(1, &m_stencilBuffer);
+ m_functions.glBindRenderbuffer(GL_RENDERBUFFER, m_stencilBuffer);
+#ifdef QT_OPENGL_ES
+ const GLenum internalFormat = GL_STENCIL_INDEX8;
+#else
+ const GLenum internalFormat = GL_STENCIL_INDEX;
+#endif
+ if (format.samples && m_functions.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) {
+ m_functions.glRenderbufferStorageMultisample(GL_RENDERBUFFER, format.samples,
+ internalFormat, width, height);
+ } else {
+ m_functions.glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, width, height);
+ }
+ }
+}
+
+QSGDefaultDepthStencilBuffer::~QSGDefaultDepthStencilBuffer()
+{
+ free();
+}
+
+void QSGDefaultDepthStencilBuffer::free()
+{
+ if (m_depthBuffer)
+ m_functions.glDeleteRenderbuffers(1, &m_depthBuffer);
+ if (m_stencilBuffer && m_stencilBuffer != m_depthBuffer)
+ m_functions.glDeleteRenderbuffers(1, &m_stencilBuffer);
+ m_depthBuffer = m_stencilBuffer = 0;
+}
+
+
+QSGDepthStencilBufferManager::~QSGDepthStencilBufferManager()
+{
+ for (Hash::const_iterator it = m_buffers.constBegin(); it != m_buffers.constEnd(); ++it) {
+ QSGDepthStencilBuffer *buffer = it.value().data();
+ buffer->free();
+ buffer->m_manager = 0;
+ }
+}
+
+QSharedPointer<QSGDepthStencilBuffer> QSGDepthStencilBufferManager::bufferForFormat(const QSGDepthStencilBuffer::Format &fmt)
+{
+ Hash::const_iterator it = m_buffers.constFind(fmt);
+ if (it != m_buffers.constEnd())
+ return it.value().toStrongRef();
+ return QSharedPointer<QSGDepthStencilBuffer>();
+}
+
+void QSGDepthStencilBufferManager::insertBuffer(const QSharedPointer<QSGDepthStencilBuffer> &buffer)
+{
+ Q_ASSERT(buffer->m_manager == 0);
+ Q_ASSERT(!m_buffers.contains(buffer->m_format));
+ buffer->m_manager = this;
+ m_buffers.insert(buffer->m_format, buffer.toWeakRef());
+}
+
+uint qHash(const QSGDepthStencilBuffer::Format &format)
+{
+ return qHash(qMakePair(format.size.width(), format.size.height()))
+ ^ (uint(format.samples) << 12) ^ (uint(format.attachments) << 28);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h b/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h
new file mode 100644
index 0000000000..0d8847feb4
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGDEPTHSTENCILBUFFER_P_H
+#define QSGDEPTHSTENCILBUFFER_P_H
+
+#include <QtCore/qsize.h>
+#include <QtGui/private/qopenglcontext_p.h>
+#include <QtGui/private/qopenglextensions_p.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qhash.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGDepthStencilBufferManager;
+
+class QSGDepthStencilBuffer
+{
+public:
+ enum Attachment
+ {
+ NoAttachment = 0x00,
+ DepthAttachment = 0x01,
+ StencilAttachment = 0x02
+ };
+ Q_DECLARE_FLAGS(Attachments, Attachment)
+
+ struct Format
+ {
+ QSize size;
+ int samples;
+ QSGDepthStencilBuffer::Attachments attachments;
+ bool operator == (const Format &other) const;
+ };
+
+ QSGDepthStencilBuffer(QOpenGLContext *context, const Format &format);
+ virtual ~QSGDepthStencilBuffer();
+
+ // Attaches this depth stencil buffer to the currently bound FBO.
+ void attach();
+ // Detaches this depth stencil buffer from the currently bound FBO.
+ void detach();
+
+ QSize size() const { return m_format.size; }
+ int samples() const { return m_format.samples; }
+ Attachments attachments() const { return m_format.attachments; }
+
+protected:
+ virtual void free() = 0;
+
+ QOpenGLExtensions m_functions;
+ QSGDepthStencilBufferManager *m_manager;
+ Format m_format;
+ GLuint m_depthBuffer;
+ GLuint m_stencilBuffer;
+
+ friend class QSGDepthStencilBufferManager;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGDepthStencilBuffer::Attachments)
+
+inline bool QSGDepthStencilBuffer::Format::operator == (const Format &other) const
+{
+ return size == other.size && samples == other.samples && attachments == other.attachments;
+}
+
+
+class QSGDefaultDepthStencilBuffer : public QSGDepthStencilBuffer
+{
+public:
+ QSGDefaultDepthStencilBuffer(QOpenGLContext *context, const Format &format);
+ virtual ~QSGDefaultDepthStencilBuffer();
+
+protected:
+ virtual void free();
+};
+
+
+class QSGDepthStencilBufferManager
+{
+public:
+ QSGDepthStencilBufferManager(QOpenGLContext *ctx) : m_context(ctx) { }
+ ~QSGDepthStencilBufferManager();
+ QOpenGLContext *context() const { return m_context; }
+ QSharedPointer<QSGDepthStencilBuffer> bufferForFormat(const QSGDepthStencilBuffer::Format &fmt);
+ void insertBuffer(const QSharedPointer<QSGDepthStencilBuffer> &buffer);
+
+private:
+ typedef QHash<QSGDepthStencilBuffer::Format, QWeakPointer<QSGDepthStencilBuffer> > Hash;
+ QOpenGLContext *m_context;
+ Hash m_buffers;
+
+ friend class QSGDepthStencilBuffer;
+};
+
+extern uint qHash(const QSGDepthStencilBuffer::Format &format);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp
index 76fdf97d80..ecfdf9b03c 100644
--- a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp
+++ b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp
@@ -62,16 +62,10 @@ static float defaultAntialiasingSpreadFunc(float glyphScale)
return range / glyphScale;
}
-QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager(QSGContext *c)
- : sgCtx(c)
- , m_threshold_func(defaultThresholdFunc)
+QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager()
+ : m_threshold_func(defaultThresholdFunc)
, m_antialiasingSpread_func(defaultAntialiasingSpreadFunc)
{
-#ifndef QT_OPENGL_ES
- m_defaultAntialiasingMode = QSGGlyphNode::HighQualitySubPixelAntialiasing;
-#else
- m_defaultAntialiasingMode = QSGGlyphNode::GrayAntialiasing;
-#endif
}
QSGDistanceFieldGlyphCacheManager::~QSGDistanceFieldGlyphCacheManager()
@@ -81,11 +75,22 @@ QSGDistanceFieldGlyphCacheManager::~QSGDistanceFieldGlyphCacheManager()
QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCacheManager::cache(const QRawFont &font)
{
- QRawFontPrivate *fontD = QRawFontPrivate::get(font);
- QHash<QFontEngine *, QSGDistanceFieldGlyphCache *>::iterator cache = m_caches.find(fontD->fontEngine);
- if (cache == m_caches.end())
- cache = m_caches.insert(fontD->fontEngine, sgCtx->createDistanceFieldGlyphCache(font));
- return cache.value();
+ QString key = QString::fromLatin1("%1_%2_%3_%4")
+ .arg(font.familyName())
+ .arg(font.styleName())
+ .arg(font.weight())
+ .arg(font.style());
+ return m_caches.value(key, 0);
+}
+
+void QSGDistanceFieldGlyphCacheManager::insertCache(const QRawFont &font, QSGDistanceFieldGlyphCache *cache)
+{
+ QString key = QString::fromLatin1("%1_%2_%3_%4")
+ .arg(font.familyName())
+ .arg(font.styleName())
+ .arg(font.weight())
+ .arg(font.style());
+ m_caches.insert(key, cache);
}
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h
index 49391a737c..4ed4c28657 100644
--- a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h
+++ b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h
@@ -58,13 +58,11 @@ class QSGContext;
class Q_QUICK_EXPORT QSGDistanceFieldGlyphCacheManager
{
public:
- QSGDistanceFieldGlyphCacheManager(QSGContext *c);
+ QSGDistanceFieldGlyphCacheManager();
~QSGDistanceFieldGlyphCacheManager();
QSGDistanceFieldGlyphCache *cache(const QRawFont &font);
-
- QSGGlyphNode::AntialiasingMode defaultAntialiasingMode() const { return m_defaultAntialiasingMode; }
- void setDefaultAntialiasingMode(QSGGlyphNode::AntialiasingMode mode) { m_defaultAntialiasingMode = mode; }
+ void insertCache(const QRawFont &font, QSGDistanceFieldGlyphCache *cache);
ThresholdFunc thresholdFunc() const { return m_threshold_func; }
void setThresholdFunc(ThresholdFunc func) { m_threshold_func = func; }
@@ -73,9 +71,7 @@ public:
void setAntialiasingSpreadFunc(AntialiasingSpreadFunc func) { m_antialiasingSpread_func = func; }
private:
- QHash<QFontEngine *, QSGDistanceFieldGlyphCache *> m_caches;
-
- QSGContext *sgCtx;
+ QHash<QString, QSGDistanceFieldGlyphCache *> m_caches;
QSGGlyphNode::AntialiasingMode m_defaultAntialiasingMode;
ThresholdFunc m_threshold_func;
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index adf4242cdc..8dadab620a 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -527,6 +527,8 @@ QPointF QQuickPath::sequentialPointAt(qreal p, qreal *angle) const
QPointF QQuickPath::sequentialPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
{
+ Q_ASSERT(p >= 0.0 && p <= 1.0);
+
if (!prevBez.isValid)
return p > .5 ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
diff --git a/src/quick/util/qquickpathinterpolator.cpp b/src/quick/util/qquickpathinterpolator.cpp
index 2b5fb62872..ee1424b70f 100644
--- a/src/quick/util/qquickpathinterpolator.cpp
+++ b/src/quick/util/qquickpathinterpolator.cpp
@@ -102,6 +102,8 @@ qreal QQuickPathInterpolator::progress() const
void QQuickPathInterpolator::setProgress(qreal progress)
{
+ progress = qMin(qMax(progress, (qreal)0.0), (qreal)1.0);
+
if (progress == _progress)
return;
_progress = progress;