diff options
author | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com> | 2009-12-15 12:29:04 (GMT) |
---|---|---|
committer | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com> | 2009-12-15 12:29:04 (GMT) |
commit | f6ebcf8eb829d9639daddfc7bfddafe4371be0ef (patch) | |
tree | b63bd867ca0a259e8aea7e50561c31bd0d372ec7 | |
parent | da918327fdaaf45774c074d911882141cf77ea7e (diff) | |
parent | d6cd6c59dae36b2890baae98f0bf94b23e5509da (diff) | |
download | Qt-f6ebcf8eb829d9639daddfc7bfddafe4371be0ef.zip Qt-f6ebcf8eb829d9639daddfc7bfddafe4371be0ef.tar.gz Qt-f6ebcf8eb829d9639daddfc7bfddafe4371be0ef.tar.bz2 |
Merge branch '4.6' of scm.dev.nokia.troll.no:qt/oslo-staging-2 into 4.6
82 files changed, 2375 insertions, 913 deletions
@@ -666,6 +666,7 @@ foreach (@modules_to_sync) { #information used after the syncing my $pri_install_classes = ""; my $pri_install_files = ""; + my $pri_install_pfiles = ""; my $libcapitals = $lib; $libcapitals =~ y/a-z/A-Z/; @@ -834,6 +835,10 @@ foreach (@modules_to_sync) { $pri_install_files.= "$pri_install_iheader ";; } } + else { + my $pri_install_iheader = fixPaths($iheader, $current_dir); + $pri_install_pfiles.= "$pri_install_iheader ";; + } } print "header created for $iheader ($header_copies)\n" if($header_copies > 0); } @@ -878,6 +883,7 @@ foreach (@modules_to_sync) { my $headers_pri_contents = ""; $headers_pri_contents .= "SYNCQT.HEADER_FILES = $pri_install_files\n"; $headers_pri_contents .= "SYNCQT.HEADER_CLASSES = $pri_install_classes\n"; + $headers_pri_contents .= "SYNCQT.PRIVATE_HEADER_FILES = $pri_install_pfiles\n"; my $headers_pri_file = "$out_basedir/include/$lib/headers.pri"; if(-e "$headers_pri_file") { open HEADERS_PRI_FILE, "<$headers_pri_file"; diff --git a/config.tests/mac/crc/main.cpp b/config.tests/mac/crc/main.cpp index 894f88b..700a4cd 100644 --- a/config.tests/mac/crc/main.cpp +++ b/config.tests/mac/crc/main.cpp @@ -71,7 +71,7 @@ private: for(int iCodes = 0; iCodes <= 0xFF; iCodes++) { ulTable[iCodes] = Reflect(iCodes, 8) << 24; for(int iPos = 0; iPos < 8; iPos++) { - ulTable[iCodes] = (ulTable[iCodes] << 1) + ulTable[iCodes] = ((ulTable[iCodes] << 1) & 0xffffffff) ^ ((ulTable[iCodes] & (1 << 31)) ? ulPolynomial : 0); } @@ -84,7 +84,7 @@ private: // Swap bit 0 for bit 7, bit 1 For bit 6, etc.... for(int iPos = 1; iPos < (cChar + 1); iPos++) { if(ulReflect & 1) { - ulValue |= (1 << (cChar - iPos)); + ulValue |= (1ul << (cChar - iPos)); } ulReflect >>= 1; } @@ -131,7 +131,7 @@ compilerSupportsFlag() cat >conftest.cpp <<EOF int main() { return 0; } EOF - "$TEST_COMPILER" "$@" -o /dev/null conftest.cpp + "$TEST_COMPILER" "$@" -o conftest.o conftest.cpp ret=$? rm -f conftest.cpp conftest.o return $ret @@ -712,6 +712,7 @@ CFG_PTMALLOC=no CFG_STL=auto CFG_PRECOMPILE=auto CFG_SEPARATE_DEBUG_INFO=auto +CFG_SEPARATE_DEBUG_INFO_NOCOPY=no CFG_REDUCE_EXPORTS=auto CFG_MMX=auto CFG_3DNOW=auto @@ -1543,6 +1544,9 @@ while [ "$#" -gt 0 ]; do separate-debug-info) if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then CFG_SEPARATE_DEBUG_INFO="$VAL" + elif [ "$VAL" = "nocopy" ] ; then + CFG_SEPARATE_DEBUG_INFO="yes" + CFG_SEPARATE_DEBUG_INFO_NOCOPY="yes" else UNKNOWN_OPT=yes fi @@ -6083,6 +6087,9 @@ if [ "$CFG_SEPARATE_DEBUG_INFO" = "yes" ]; then QMakeVar add QMAKE_CXXFLAGS -g QMAKE_CONFIG="$QMAKE_CONFIG separate_debug_info" fi +if [ "$CFG_SEPARATE_DEBUG_INFO_NOCOPY" = "yes" ] ; then + QMAKE_CONFIG="$QMAKE_CONFIG separate_debug_info_nocopy" +fi [ "$CFG_MMX" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG mmx" [ "$CFG_3DNOW" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG 3dnow" [ "$CFG_SSE" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG sse" diff --git a/demos/demos.pro b/demos/demos.pro index a943bfd..5a9b6db 100644 --- a/demos/demos.pro +++ b/demos/demos.pro @@ -20,7 +20,24 @@ symbian: SUBDIRS = \ demos_shared \ demos_deform \ demos_pathstroke - + +wince*: SUBDIRS = \ + demos_shared \ + demos_deform \ + demos_gradients \ + demos_pathstroke \ + demos_affine \ + demos_composition \ + demos_books \ + demos_interview \ + demos_mainwindow \ + demos_spreadsheet \ + demos_textedit \ + # demos_chip \ + demos_embeddeddialogs \ + demos_undo \ + demos_sub-attaq + contains(QT_CONFIG, opengl):!contains(QT_CONFIG, opengles1):!contains(QT_CONFIG, opengles1cl):!contains(QT_CONFIG, opengles2):{ SUBDIRS += demos_boxes } @@ -33,7 +50,7 @@ wince*|symbian|embedded|x11: SUBDIRS += embedded !cross_compile:{ contains(QT_BUILD_PARTS, tools):{ !wince*:SUBDIRS += demos_sqlbrowser demos_qtdemo -wince*: SUBDIRS += demos_sqlbrowser +wince*:SUBDIRS += demos_sqlbrowser } } contains(QT_CONFIG, phonon):!static:SUBDIRS += demos_mediaplayer diff --git a/mkspecs/features/unix/separate_debug_info.prf b/mkspecs/features/unix/separate_debug_info.prf index 0c95baf..c675828 100644 --- a/mkspecs/features/unix/separate_debug_info.prf +++ b/mkspecs/features/unix/separate_debug_info.prf @@ -1,5 +1,5 @@ -!staticlib:!static:!contains(TEMPLATE, subdirs):!isEmpty(QMAKE_OBJCOPY) { +!separate_debug_info_nocopy:!staticlib:!static:!contains(TEMPLATE, subdirs):!isEmpty(QMAKE_OBJCOPY) { QMAKE_SEPARATE_DEBUG_INFO = (test -z \"$(DESTDIR)\" || cd \"$(DESTDIR)\" ; targ=`basename $(TARGET)`; $$QMAKE_OBJCOPY --only-keep-debug \"\$\$targ\" \"\$\$targ.debug\" && $$QMAKE_OBJCOPY --strip-debug \"\$\$targ\" && $$QMAKE_OBJCOPY --add-gnu-debuglink=\"\$\$targ.debug\" \"\$\$targ\" && chmod -x \"\$\$targ.debug\" ) ; QMAKE_INSTALL_SEPARATE_DEBUG_INFO = test -z "$(DESTDIR)" || cd \"$(DESTDIR)\" ; $(INSTALL_FILE) `basename $(TARGET)`.debug $(INSTALL_ROOT)/\$\$target_path/ diff --git a/mkspecs/unsupported/linux-host-g++/qmake.conf b/mkspecs/unsupported/linux-host-g++/qmake.conf index 237477c..8a480c4 100644 --- a/mkspecs/unsupported/linux-host-g++/qmake.conf +++ b/mkspecs/unsupported/linux-host-g++/qmake.conf @@ -134,5 +134,5 @@ QMAKE_MKDIR = mkdir -p QMAKE_INSTALL_FILE = install -m 644 -p QMAKE_INSTALL_PROGRAM = install -m 755 -p -include(../common/unix.conf) +include(../../common/unix.conf) load(qt_config) diff --git a/projects.pro b/projects.pro index 497acd0..d405a5b 100644 --- a/projects.pro +++ b/projects.pro @@ -48,7 +48,7 @@ for(PROJECT, $$list($$lower($$unique(QT_BUILD_PARTS)))) { contains(QT_BUILD_PARTS, tools) { include(translations/translations.pri) # ts targets } else { - SUBDIRS += tools/linguist/lrelease + !wince*:!symbian:SUBDIRS += tools/linguist/lrelease } SUBDIRS += translations # qm build step } else:isEqual(PROJECT, qmake) { diff --git a/src/corelib/codecs/qtextcodec.h b/src/corelib/codecs/qtextcodec.h index f831700..6170272 100644 --- a/src/corelib/codecs/qtextcodec.h +++ b/src/corelib/codecs/qtextcodec.h @@ -161,7 +161,7 @@ public: QByteArray fromUnicode(const QString& str); QByteArray fromUnicode(const QChar *uc, int len); #ifdef QT3_SUPPORT - QByteArray fromUnicode(const QString& uc, int& lenInOut); + QT3_SUPPORT QByteArray fromUnicode(const QString& uc, int& lenInOut); #endif bool hasFailure() const; private: diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 37b0ea1..e4c4e3f 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -144,7 +144,7 @@ QString QFSFileEnginePrivate::canonicalized(const QString &path) return path; #endif // Mac OS X 10.5.x doesn't support the realpath(X,0) extenstion we use here. -#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) || defined(Q_OS_SYMBIAN) +#if defined(Q_OS_LINIX) || defined(Q_OS_SYMBIAN) char *ret = realpath(path.toLocal8Bit().constData(), (char*)0); if (ret) { QString canonicalPath = QDir::cleanPath(QString::fromLocal8Bit(ret)); diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 37161bc..c78af3c 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -275,7 +275,7 @@ QProcessEnvironment &QProcessEnvironment::operator=(const QProcessEnvironment &o */ bool QProcessEnvironment::operator==(const QProcessEnvironment &other) const { - return d->hash == other.d->hash; + return d == other.d || (d && other.d && d->hash == other.d->hash); } /*! @@ -334,6 +334,7 @@ bool QProcessEnvironment::contains(const QString &name) const */ void QProcessEnvironment::insert(const QString &name, const QString &value) { + // d detaches from null d->hash.insert(prepareName(name), prepareValue(value)); } diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp index 5885591..d0dc7be 100644 --- a/src/corelib/kernel/qcore_unix.cpp +++ b/src/corelib/kernel/qcore_unix.cpp @@ -129,7 +129,7 @@ static inline bool time_update(struct timeval *tv, const struct timeval &start, // clock source is monotonic, so we can recalculate how much timeout is left struct timeval now = qt_gettime(); *tv = timeout + start - now; - return true; + return tv->tv_sec >= 0; } int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, @@ -154,7 +154,8 @@ int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, // recalculate the timeout if (!time_update(&timeout, start, *orig_timeout)) { - // clock reset, fake timeout error + // timeout during update + // or clock reset, fake timeout error return 0; } } diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index c6eef5e..c305341 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -509,7 +509,11 @@ LRESULT CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp) } } } +#ifdef Q_OS_WINCE + return 0; +#else return CallNextHookEx(0, code, wp, lp); +#endif } static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher) @@ -636,11 +640,13 @@ void QEventDispatcherWin32::createInternalHwnd() return; d->internalHwnd = qt_create_internal_window(this); +#ifndef Q_OS_WINCE // setup GetMessage hook needed to drive our posted events d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId()); if (!d->getMessageHook) { qFatal("Qt: INTERNALL ERROR: failed to install GetMessage hook"); } +#endif // register all socket notifiers QList<int> sockets = (d->sn_read.keys().toSet() @@ -731,6 +737,11 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) } } if (haveMessage) { +#ifdef Q_OS_WINCE + // WinCE doesn't support hooks at all, so we have to call this by hand :( + (void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg); +#endif + if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) { if (seenWM_QT_SENDPOSTEDEVENTS) { needWM_QT_SENDPOSTEDEVENTS = true; @@ -1065,9 +1076,11 @@ void QEventDispatcherWin32::closingDown() d->timerVec.clear(); d->timerDict.clear(); +#ifndef Q_OS_WINCE if (d->getMessageHook) UnhookWindowsHookEx(d->getMessageHook); d->getMessageHook = 0; +#endif } bool QEventDispatcherWin32::event(QEvent *e) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 6e6da19..72d6786 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -2648,6 +2648,7 @@ const char* QMetaClassInfo::value() const */ int QMetaObjectPrivate::originalClone(const QMetaObject *mobj, int local_method_index) { + Q_ASSERT(local_method_index < get(mobj)->methodCount); int handle = get(mobj)->methodData + 5 * local_method_index; while (mobj->d.data[handle + 4] & MethodCloned) { Q_ASSERT(local_method_index > 0); diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 85915c2..4370ee0 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -2850,6 +2850,27 @@ void QObject::disconnectNotify(const char *) { } +/* \internal + convert a signal index from the method range to the signal range + */ +static int methodIndexToSignalIndex(const QMetaObject *metaObject, int signal_index) +{ + if (signal_index < 0) + return signal_index; + while (metaObject && metaObject->methodOffset() > signal_index) + metaObject = metaObject->superClass(); + + if (metaObject) { + int signalOffset, methodOffset; + computeOffsets(metaObject, &signalOffset, &methodOffset); + if (signal_index < metaObject->methodCount()) + signal_index = QMetaObjectPrivate::originalClone(metaObject, signal_index - methodOffset) + signalOffset; + else + signal_index = signal_index - methodOffset + signalOffset; + } + return signal_index; +} + /*!\internal \a types is a 0-terminated vector of meta types for queued connections. @@ -2860,16 +2881,7 @@ void QObject::disconnectNotify(const char *) bool QMetaObject::connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type, int *types) { - if (signal_index > 0) { - const QMetaObject *mo = sender->metaObject(); - while (mo && mo->methodOffset() > signal_index) - mo = mo->superClass(); - if (mo) { - int signalOffset, methodOffset; - computeOffsets(mo, &signalOffset, &methodOffset); - signal_index = QMetaObjectPrivate::originalClone(mo, signal_index - methodOffset) + signalOffset; - } - } + signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); return QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, type, types); } @@ -2938,16 +2950,7 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, bool QMetaObject::disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index) { - if (signal_index > 0) { - const QMetaObject *mo = sender->metaObject(); - while (mo && mo->methodOffset() > signal_index) - mo = mo->superClass(); - if (mo) { - int signalOffset, methodOffset; - computeOffsets(mo, &signalOffset, &methodOffset); - signal_index = QMetaObjectPrivate::originalClone(mo, signal_index - methodOffset) + signalOffset; - } - } + signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); return QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index); } diff --git a/src/corelib/tools/qcache.h b/src/corelib/tools/qcache.h index 086a52f..66f9f73 100644 --- a/src/corelib/tools/qcache.h +++ b/src/corelib/tools/qcache.h @@ -70,9 +70,9 @@ class QCache if (l == &n) l = n.p; if (f == &n) f = n.n; total -= n.c; - T *object = n.t; + T *obj = n.t; hash.remove(*n.keyPtr); - delete object; + delete obj; } inline T *relink(const Key &key) { typename QHash<Key, Node>::iterator i = hash.find(key); diff --git a/src/dbus/qdbusargument_p.h b/src/dbus/qdbusargument_p.h index 47c5e62..17302b4 100644 --- a/src/dbus/qdbusargument_p.h +++ b/src/dbus/qdbusargument_p.h @@ -54,7 +54,7 @@ // #include <qdbusargument.h> -#include <qdbus_symbols_p.h> +#include "qdbus_symbols_p.h" QT_BEGIN_NAMESPACE diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index b65e101..d6f7598 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -67,7 +67,7 @@ #include <QtCore/qvarlengtharray.h> #include <QtCore/qvector.h> -#include <qdbus_symbols_p.h> +#include "qdbus_symbols_p.h" #include <qdbusmessage.h> diff --git a/src/dbus/qdbusconnectioninterface.cpp b/src/dbus/qdbusconnectioninterface.cpp index 0f9a67f..ec61859 100644 --- a/src/dbus/qdbusconnectioninterface.cpp +++ b/src/dbus/qdbusconnectioninterface.cpp @@ -49,7 +49,7 @@ #include <QtCore/QVariant> #include <QtCore/QDebug> -#include <qdbus_symbols_p.h> // for the DBUS_* constants +#include "qdbus_symbols_p.h" // for the DBUS_* constants QT_BEGIN_NAMESPACE diff --git a/src/dbus/qdbuserror.cpp b/src/dbus/qdbuserror.cpp index 5c2fa2b..a48b878 100644 --- a/src/dbus/qdbuserror.cpp +++ b/src/dbus/qdbuserror.cpp @@ -44,7 +44,7 @@ #include <qdebug.h> #include <qvarlengtharray.h> -#include <qdbus_symbols_p.h> +#include "qdbus_symbols_p.h" #include "qdbusmessage.h" #include "qdbusmessage_p.h" diff --git a/src/dbus/qdbusintegrator_p.h b/src/dbus/qdbusintegrator_p.h index 5b18aca..85c6cb2 100644 --- a/src/dbus/qdbusintegrator_p.h +++ b/src/dbus/qdbusintegrator_p.h @@ -54,7 +54,7 @@ #ifndef QDBUSINTEGRATOR_P_H #define QDBUSINTEGRATOR_P_H -#include <qdbus_symbols_p.h> +#include "qdbus_symbols_p.h" #include "qcoreevent.h" #include "qeventloop.h" diff --git a/src/dbus/qdbusinterface.cpp b/src/dbus/qdbusinterface.cpp index d0a693f..c05e6a9 100644 --- a/src/dbus/qdbusinterface.cpp +++ b/src/dbus/qdbusinterface.cpp @@ -41,7 +41,7 @@ #include "qdbusinterface.h" -#include <qdbus_symbols_p.h> +#include "qdbus_symbols_p.h" #include <QtCore/qpointer.h> #include <QtCore/qstringlist.h> diff --git a/src/dbus/qdbusinterface_p.h b/src/dbus/qdbusinterface_p.h index 3d11af1..a601608 100644 --- a/src/dbus/qdbusinterface_p.h +++ b/src/dbus/qdbusinterface_p.h @@ -54,8 +54,8 @@ #ifndef QDBUSINTERFACEPRIVATE_H #define QDBUSINTERFACEPRIVATE_H -#include <qdbusabstractinterface_p.h> -#include <qdbusmetaobject_p.h> +#include "qdbusabstractinterface_p.h" +#include "qdbusmetaobject_p.h" #include <qdbusinterface.h> QT_BEGIN_NAMESPACE diff --git a/src/dbus/qdbusinternalfilters.cpp b/src/dbus/qdbusinternalfilters.cpp index acd04d3..37110c5 100644 --- a/src/dbus/qdbusinternalfilters.cpp +++ b/src/dbus/qdbusinternalfilters.cpp @@ -41,7 +41,7 @@ #include "qdbusconnection_p.h" -#include <qdbus_symbols_p.h> +#include "qdbus_symbols_p.h" #include <QtCore/qcoreapplication.h> #include <QtCore/qmetaobject.h> #include <QtCore/qstringlist.h> diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp index 4f1950b..a37ba1f 100644 --- a/src/dbus/qdbusmessage.cpp +++ b/src/dbus/qdbusmessage.cpp @@ -44,7 +44,7 @@ #include <qdebug.h> #include <qstringlist.h> -#include <qdbus_symbols_p.h> +#include "qdbus_symbols_p.h" #include "qdbusargument_p.h" #include "qdbuserror.h" diff --git a/src/dbus/qdbusmetatype.cpp b/src/dbus/qdbusmetatype.cpp index 237aea3..afa3bbf 100644 --- a/src/dbus/qdbusmetatype.cpp +++ b/src/dbus/qdbusmetatype.cpp @@ -42,7 +42,7 @@ #include "qdbusmetatype.h" #include <string.h> -#include <qdbus_symbols_p.h> +#include "qdbus_symbols_p.h" #include <qbytearray.h> #include <qglobal.h> diff --git a/src/dbus/qdbusutil.cpp b/src/dbus/qdbusutil.cpp index bf5a739..01b1dbd 100644 --- a/src/dbus/qdbusutil.cpp +++ b/src/dbus/qdbusutil.cpp @@ -41,7 +41,7 @@ #include "qdbusutil_p.h" -#include <qdbus_symbols_p.h> +#include "qdbus_symbols_p.h" #include <QtCore/qstringlist.h> diff --git a/src/dbus/qdbusxmlparser_p.h b/src/dbus/qdbusxmlparser_p.h index 3dbae1b..1a0523b 100644 --- a/src/dbus/qdbusxmlparser_p.h +++ b/src/dbus/qdbusxmlparser_p.h @@ -56,7 +56,7 @@ #include <QtCore/qmap.h> #include <QtXml/qdom.h> #include <qdbusmacros.h> -#include <qdbusintrospection_p.h> +#include "qdbusintrospection_p.h" QT_BEGIN_NAMESPACE diff --git a/src/gui/dialogs/dialogs.pri b/src/gui/dialogs/dialogs.pri index b9fad41..63f64a2 100644 --- a/src/gui/dialogs/dialogs.pri +++ b/src/gui/dialogs/dialogs.pri @@ -28,13 +28,27 @@ HEADERS += \ dialogs/qprintpreviewdialog.h !embedded:mac { - OBJECTIVE_SOURCES += dialogs/qcolordialog_mac.mm \ - dialogs/qfiledialog_mac.mm \ + OBJECTIVE_SOURCES += dialogs/qfiledialog_mac.mm \ dialogs/qfontdialog_mac.mm \ dialogs/qnspanelproxy_mac.mm \ dialogs/qpagesetupdialog_mac.mm \ dialogs/qprintdialog_mac.mm + +# Compile qcolordialog_mac.mm with exception support, disregarding the -no-exceptions +# configure option. (qcolordialog_mac needs to catch exceptions thrown by cocoa) + EXCEPTION_SOURCES = dialogs/qcolordialog_mac.mm + exceptions_compiler.commands = $$QMAKE_CXX -c + exceptions_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} + exceptions_compiler.commands += -fexceptions + exceptions_compiler.dependency_type = TYPE_C + exceptions_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} + exceptions_compiler.input = EXCEPTION_SOURCES + exceptions_compiler.variable_out = OBJECTS + exceptions_compiler.name = compiling[exceptopns] ${QMAKE_FILE_IN} + silent:exceptions_compiler.commands = @echo compiling[exceptopns] ${QMAKE_FILE_IN} && $$exceptions_compiler.commands + QMAKE_EXTRA_COMPILERS += exceptions_compiler } + win32 { HEADERS += dialogs/qwizard_win_p.h SOURCES += dialogs/qdialogsbinarycompat_win.cpp \ diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index d6cabaa..a523bab 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -313,7 +313,10 @@ QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offse // Shortcut, no cache for childless pixmap items... const QGraphicsItem *item = graphicsItem(); if (system == Qt::LogicalCoordinates && mode == QGraphicsEffect::NoPad && item && isPixmap()) { - return ((QGraphicsPixmapItem *) item)->pixmap(); + const QGraphicsPixmapItem *pixmapItem = static_cast<const QGraphicsPixmapItem *>(item); + if (offset) + *offset = pixmapItem->offset().toPoint(); + return pixmapItem->pixmap(); } if (system == Qt::DeviceCoordinates && item @@ -371,10 +374,14 @@ QGraphicsEffectSourcePrivate::~QGraphicsEffectSourcePrivate() invalidateCache(); } -void QGraphicsEffectSourcePrivate::invalidateCache(bool effectRectChanged) const +void QGraphicsEffectSourcePrivate::invalidateCache(InvalidateReason reason) const { - if (effectRectChanged && m_cachedMode != QGraphicsEffect::PadToEffectiveBoundingRect) + if (m_cachedMode != QGraphicsEffect::PadToEffectiveBoundingRect + && (reason == EffectRectChanged + || reason == TransformChanged + && m_cachedSystem == Qt::LogicalCoordinates)) return; + QPixmapCache::remove(m_cacheKey); } @@ -520,7 +527,7 @@ void QGraphicsEffect::updateBoundingRect() Q_D(QGraphicsEffect); if (d->source) { d->source->d_func()->effectBoundingRectChanged(); - d->source->d_func()->invalidateCache(true); + d->source->d_func()->invalidateCache(QGraphicsEffectSourcePrivate::EffectRectChanged); } } @@ -837,22 +844,19 @@ QRectF QGraphicsBlurEffect::boundingRectFor(const QRectF &rect) const void QGraphicsBlurEffect::draw(QPainter *painter) { Q_D(QGraphicsBlurEffect); - if (d->filter->radius() <= 0) { + if (d->filter->radius() < 1) { drawSource(painter); return; } PixmapPadMode mode = PadToEffectiveBoundingRect; if (painter->paintEngine()->type() == QPaintEngine::OpenGL2) - mode = PadToTransparentBorder; + mode = NoPad; // Draw pixmap in device coordinates to avoid pixmap scaling. QPoint offset; - const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset, mode); - QTransform restoreTransform = painter->worldTransform(); - painter->setWorldTransform(QTransform()); + QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, mode); d->filter->draw(painter, offset, pixmap); - painter->setWorldTransform(restoreTransform); } /*! @@ -1033,7 +1037,7 @@ void QGraphicsDropShadowEffect::draw(QPainter *painter) PixmapPadMode mode = PadToEffectiveBoundingRect; if (painter->paintEngine()->type() == QPaintEngine::OpenGL2) - mode = PadToTransparentBorder; + mode = NoPad; // Draw pixmap in device coordinates to avoid pixmap scaling. QPoint offset; diff --git a/src/gui/effects/qgraphicseffect_p.h b/src/gui/effects/qgraphicseffect_p.h index 0011eef..cab7a48 100644 --- a/src/gui/effects/qgraphicseffect_p.h +++ b/src/gui/effects/qgraphicseffect_p.h @@ -108,6 +108,13 @@ public: , m_cachedMode(QGraphicsEffect::PadToTransparentBorder) {} + enum InvalidateReason + { + TransformChanged, + EffectRectChanged, + SourceChanged + }; + virtual ~QGraphicsEffectSourcePrivate(); virtual void detach() = 0; virtual QRectF boundingRect(Qt::CoordinateSystem system) const = 0; @@ -121,7 +128,9 @@ public: virtual QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset = 0, QGraphicsEffect::PixmapPadMode mode = QGraphicsEffect::PadToTransparentBorder) const = 0; virtual void effectBoundingRectChanged() = 0; - void invalidateCache(bool effectRectChanged = false) const; + + void invalidateCache(InvalidateReason reason = SourceChanged) const; + Qt::CoordinateSystem currentCachedSystem() const { return m_cachedSystem; } friend class QGraphicsScenePrivate; friend class QGraphicsItem; diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index d955f16..fbfd8e6 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -7177,9 +7177,16 @@ void QGraphicsItem::prepareGeometryChange() QGraphicsItem *parent = this; while ((parent = parent->d_ptr->parent)) { - parent->d_ptr->dirtyChildrenBoundingRect = 1; + QGraphicsItemPrivate *parentp = parent->d_ptr.data(); + parentp->dirtyChildrenBoundingRect = 1; // ### Only do this if the parent's effect applies to the entire subtree. - parent->d_ptr->notifyBoundingRectChanged = 1; + parentp->notifyBoundingRectChanged = 1; +#ifndef QT_NO_GRAPHICSEFFECT + if (parentp->scene && parentp->graphicsEffect) { + parentp->notifyInvalidated = 1; + static_cast<QGraphicsItemEffectSourcePrivate *>(parentp->graphicsEffect->d_func()->source->d_func())->invalidateCache(); + } +#endif } } @@ -10717,7 +10724,6 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context"); return QPixmap(); } - if (!item->d_ptr->scene) return QPixmap(); QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func(); @@ -10725,9 +10731,11 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP const QRectF sourceRect = boundingRect(system); QRectF effectRectF; + bool unpadded = false; if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) { if (info) { effectRectF = item->graphicsEffect()->boundingRectFor(boundingRect(Qt::DeviceCoordinates)); + unpadded = (effectRectF.size() == sourceRect.size()); if (info && system == Qt::LogicalCoordinates) effectRectF = info->painter->worldTransform().inverted().mapRect(effectRectF); } else { @@ -10739,6 +10747,7 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP effectRectF = sourceRect.adjusted(-1.5, -1.5, 1.5, 1.5); } else { effectRectF = sourceRect; + unpadded = true; } QRect effectRect = effectRectF.toAlignedRect(); @@ -10746,6 +10755,14 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP if (offset) *offset = effectRect.topLeft(); + bool untransformed = !deviceCoordinates + || info->painter->worldTransform().type() <= QTransform::TxTranslate; + if (untransformed && unpadded && isPixmap()) { + if (offset) + *offset = boundingRect(system).topLeft().toPoint(); + return static_cast<QGraphicsPixmapItem *>(item)->pixmap(); + } + if (deviceCoordinates) { // Clip to viewport rect. int left, top, right, bottom; @@ -10773,12 +10790,6 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP if (effectRect.isEmpty()) return QPixmap(); - if (system == Qt::LogicalCoordinates - && effectRect.size() == sourceRect.size() - && isPixmap()) { - return static_cast<QGraphicsPixmapItem *>(item)->pixmap(); - } - QPixmap pixmap(effectRect.size()); pixmap.fill(Qt::transparent); QPainter pixmapPainter(&pixmap); diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 2af90b8..182a3f5 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -614,6 +614,19 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) if (item == lastActivePanel) lastActivePanel = 0; + // Cancel active touches + { + QMap<int, QGraphicsItem *>::iterator it = itemForTouchPointId.begin(); + while (it != itemForTouchPointId.end()) { + if (it.value() == item) { + sceneCurrentTouchPoints.remove(it.key()); + it = itemForTouchPointId.erase(it); + } else { + ++it; + } + } + } + // Disable selectionChanged() for individual items ++selectionChanging; int oldSelectedItemsSize = selectedItems.size(); @@ -4658,10 +4671,13 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * painter->setWorldTransform(*transformPtr); painter->setOpacity(opacity); - if (sourced->lastEffectTransform != painter->worldTransform()) { + if (sourced->currentCachedSystem() != Qt::LogicalCoordinates + && sourced->lastEffectTransform != painter->worldTransform()) + { sourced->lastEffectTransform = painter->worldTransform(); - sourced->invalidateCache(); + sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged); } + item->d_ptr->graphicsEffect->draw(painter); painter->setWorldTransform(restoreTransform); sourced->info = 0; @@ -5680,17 +5696,22 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve touchEvent->setAccepted(acceptTouchEvents); res = acceptTouchEvents && sendEvent(item, touchEvent); eventAccepted = touchEvent->isAccepted(); - item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted); + if (itemForTouchPointId.value(touchEvent->touchPoints().first().id()) == 0) { + // item was deleted + item = 0; + } else { + item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted); + } touchEvent->spont = false; if (res && eventAccepted) { // the first item to accept the TouchBegin gets an implicit grab. for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i); - itemForTouchPointId[touchPoint.id()] = item; + itemForTouchPointId[touchPoint.id()] = item; // can be zero } break; } - if (item->isPanel()) + if (item && item->isPanel()) break; } diff --git a/src/gui/image/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp index 3723500..9c7c28e 100644 --- a/src/gui/image/qpixmapfilter.cpp +++ b/src/gui/image/qpixmapfilter.cpp @@ -52,6 +52,10 @@ #include "private/qgraphicssystem_p.h" #include "private/qpaintengineex_p.h" #include "private/qpaintengine_raster_p.h" +#include "qmath.h" +#include "private/qmath_p.h" +#include "private/qmemrotate_p.h" +#include "private/qdrawhelper_p.h" #ifndef QT_NO_GRAPHICSEFFECT QT_BEGIN_NAMESPACE @@ -585,106 +589,343 @@ QGraphicsBlurEffect::BlurHints QPixmapBlurFilter::blurHints() const return d->hints; } +const qreal radiusScale = qreal(2.5); + /*! \internal */ QRectF QPixmapBlurFilter::boundingRectFor(const QRectF &rect) const { Q_D(const QPixmapBlurFilter); - const qreal delta = d->radius + 1; + const qreal delta = radiusScale * d->radius + 1; return rect.adjusted(-delta, -delta, delta, delta); } // Blur the image according to the blur radius // Based on exponential blur algorithm by Jani Huhtanen -// (maximum radius is set to 16) -static QImage blurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly = false) + +template <int aprec, int zprec, bool alphaOnly> +static inline void blurrow( QImage & im, int line, int alpha); + +/* +* expblur(QImage &img, int radius) +* +* In-place blur of image 'img' with kernel +* of approximate radius 'radius'. +* +* Blurs with two sided exponential impulse +* response. +* +* aprec = precision of alpha parameter +* in fixed-point format 0.aprec +* +* zprec = precision of state parameters +* zR,zG,zB and zA in fp format 8.zprec +*/ +template <int aprec, int zprec, bool alphaOnly> +void expblur(QImage &img, qreal radius, bool improvedQuality = false, int transposed = 0) +{ + // halve the radius if we're using two passes + if (improvedQuality) + radius *= qreal(0.5); + + Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied + || img.format() == QImage::Format_RGB32); + + // choose the alpha such that pixels at radius distance from a fully + // saturated pixel will have an alpha component of no greater than + // the cutOffIntensity + const qreal cutOffIntensity = 2; + int alpha = radius <= qreal(1e-5) + ? ((1 << aprec)-1) + : qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / radius))); + + int img_height = img.height(); + for (int row = 0; row < img_height; ++row) { + for (int i = 0; i <= improvedQuality; ++i) + blurrow<aprec, zprec, alphaOnly>(img, row, alpha); + } + + QImage temp(img.height(), img.width(), img.format()); + if (transposed >= 0) { + if (img.depth() == 8) { + qt_memrotate270(reinterpret_cast<const quint8*>(img.bits()), + img.width(), img.height(), img.bytesPerLine(), + reinterpret_cast<quint8*>(temp.bits()), + temp.bytesPerLine()); + } else { + qt_memrotate270(reinterpret_cast<const quint32*>(img.bits()), + img.width(), img.height(), img.bytesPerLine(), + reinterpret_cast<quint32*>(temp.bits()), + temp.bytesPerLine()); + } + } else { + if (img.depth() == 8) { + qt_memrotate90(reinterpret_cast<const quint8*>(img.bits()), + img.width(), img.height(), img.bytesPerLine(), + reinterpret_cast<quint8*>(temp.bits()), + temp.bytesPerLine()); + } else { + qt_memrotate90(reinterpret_cast<const quint32*>(img.bits()), + img.width(), img.height(), img.bytesPerLine(), + reinterpret_cast<quint32*>(temp.bits()), + temp.bytesPerLine()); + } + } + + img_height = temp.height(); + for (int row = 0; row < img_height; ++row) { + for (int i = 0; i <= improvedQuality; ++i) + blurrow<aprec, zprec, alphaOnly>(temp, row, alpha); + } + + if (transposed == 0) { + qt_memrotate90(reinterpret_cast<const quint32*>(temp.bits()), + temp.width(), temp.height(), temp.bytesPerLine(), + reinterpret_cast<quint32*>(img.bits()), + img.bytesPerLine()); + } else { + img = temp; + } +} + +template <int shift> +static inline int static_shift(int value) +{ + if (shift == 0) + return value; + else if (shift > 0) + return value << (uint(shift) & 0x1f); + else + return value >> (uint(-shift) & 0x1f); +} + +template<int aprec, int zprec> +static inline void blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, int alpha) { - int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; - int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; + QRgb *pixel = (QRgb *)bptr; + +#define Z_MASK (0xff << zprec) + const int A_zprec = static_shift<zprec - 24>(*pixel) & Z_MASK; + const int R_zprec = static_shift<zprec - 16>(*pixel) & Z_MASK; + const int G_zprec = static_shift<zprec - 8>(*pixel) & Z_MASK; + const int B_zprec = static_shift<zprec>(*pixel) & Z_MASK; +#undef Z_MASK + + const int zR_zprec = zR >> aprec; + const int zG_zprec = zG >> aprec; + const int zB_zprec = zB >> aprec; + const int zA_zprec = zA >> aprec; + + zR += alpha * (R_zprec - zR_zprec); + zG += alpha * (G_zprec - zG_zprec); + zB += alpha * (B_zprec - zB_zprec); + zA += alpha * (A_zprec - zA_zprec); + +#define ZA_MASK (0xff << (zprec + aprec)) + *pixel = + static_shift<24 - zprec - aprec>(zA & ZA_MASK) + | static_shift<16 - zprec - aprec>(zR & ZA_MASK) + | static_shift<8 - zprec - aprec>(zG & ZA_MASK) + | static_shift<-zprec - aprec>(zB & ZA_MASK); +#undef ZA_MASK +} - QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); - int r1 = rect.top(); - int r2 = rect.bottom(); - int c1 = rect.left(); - int c2 = rect.right(); +const int alphaIndex = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); - int bpl = result.bytesPerLine(); - int rgba[4]; - unsigned char* p; +template<int aprec, int zprec> +static inline void blurinner_alphaOnly(uchar *bptr, int &z, int alpha) +{ + const int A_zprec = int(*(bptr)) << zprec; + const int z_zprec = z >> aprec; + z += alpha * (A_zprec - z_zprec); + *(bptr) = z >> (zprec + aprec); +} - int i1 = 0; - int i2 = 3; +template<int aprec, int zprec, bool alphaOnly> +static inline void blurrow(QImage & im, int line, int alpha) +{ + uchar *bptr = im.scanLine(line); - if (alphaOnly) - i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); + int zR = 0, zG = 0, zB = 0, zA = 0; + + if (alphaOnly && im.format() != QImage::Format_Indexed8) + bptr += alphaIndex; - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r1) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + const int stride = im.depth() >> 3; + const int im_width = im.width(); + for (int index = 0; index < im_width; ++index) { + if (alphaOnly) + blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha); + else + blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha); + bptr += stride; + } + + bptr -= stride; + + for (int index = im_width - 2; index >= 0; --index) { + bptr -= stride; + if (alphaOnly) + blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha); + else + blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha); + } +} + +#define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) ) +#define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) ) + +Q_GUI_EXPORT QImage qt_halfScaled(const QImage &source) +{ + QImage srcImage = source; + + if (source.format() == QImage::Format_Indexed8) { + // assumes grayscale + QImage dest(source.width() / 2, source.height() / 2, srcImage.format()); + + const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits()); + int sx = srcImage.bytesPerLine(); + int sx2 = sx << 1; + + uchar *dst = reinterpret_cast<uchar*>(dest.bits()); + int dx = dest.bytesPerLine(); + int ww = dest.width(); + int hh = dest.height(); + + for (int y = hh; y; --y, dst += dx, src += sx2) { + const uchar *p1 = src; + const uchar *p2 = src + sx; + uchar *q = dst; + for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2) + *q = ((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2; + } - p += bpl; - for (int j = r1; j < r2; j++, p += bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + return dest; + } else if (source.format() == QImage::Format_ARGB8565_Premultiplied) { + QImage dest(source.width() / 2, source.height() / 2, srcImage.format()); + + const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits()); + int sx = srcImage.bytesPerLine(); + int sx2 = sx << 1; + + uchar *dst = reinterpret_cast<uchar*>(dest.bits()); + int dx = dest.bytesPerLine(); + int ww = dest.width(); + int hh = dest.height(); + + for (int y = hh; y; --y, dst += dx, src += sx2) { + const uchar *p1 = src; + const uchar *p2 = src + sx; + uchar *q = dst; + for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) { + // alpha + q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3])); + // rgb + const quint16 p16_1 = (p1[2] << 8) | p1[1]; + const quint16 p16_2 = (p1[5] << 8) | p1[4]; + const quint16 p16_3 = (p2[2] << 8) | p2[1]; + const quint16 p16_4 = (p2[5] << 8) | p2[4]; + const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4)); + q[1] = result & 0xff; + q[2] = result >> 8; + } + } + + return dest; + } else if (source.format() != QImage::Format_ARGB32_Premultiplied + && source.format() != QImage::Format_RGB32) + { + srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied); } - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c1 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + QImage dest(source.width() / 2, source.height() / 2, srcImage.format()); + + const quint32 *src = reinterpret_cast<const quint32*>(const_cast<const QImage &>(srcImage).bits()); + int sx = srcImage.bytesPerLine() >> 2; + int sx2 = sx << 1; - p += 4; - for (int j = c1; j < c2; j++, p += 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + quint32 *dst = reinterpret_cast<quint32*>(dest.bits()); + int dx = dest.bytesPerLine() >> 2; + int ww = dest.width(); + int hh = dest.height(); + + for (int y = hh; y; --y, dst += dx, src += sx2) { + const quint32 *p1 = src; + const quint32 *p2 = src + sx; + quint32 *q = dst; + for (int x = ww; x; --x, q++, p1 += 2, p2 += 2) + *q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1])); } - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r2) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + return dest; +} - p -= bpl; - for (int j = r1; j < r2; j++, p -= bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; +Q_GUI_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0) +{ + if (blurImage.format() != QImage::Format_ARGB32_Premultiplied + && blurImage.format() != QImage::Format_RGB32) + { + blurImage = blurImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); } - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c2 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + qreal scale = 1; + if (radius >= 4) { + blurImage = qt_halfScaled(blurImage); + scale = 2; + radius *= qreal(0.5); + } - p -= 4; - for (int j = c1; j < c2; j++, p -= 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + if (alphaOnly) + expblur<12, 10, true>(blurImage, radius, quality, transposed); + else + expblur<12, 10, false>(blurImage, radius, quality, transposed); + + if (p) { + p->scale(scale, scale); + p->setRenderHint(QPainter::SmoothPixmapTransform); + p->drawImage(QRect(0, 0, blurImage.width(), blurImage.height()), blurImage); } +} - return result; +Q_GUI_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0) +{ + if (blurImage.format() == QImage::Format_Indexed8) + expblur<12, 10, true>(blurImage, radius, quality, transposed); + else + expblur<12, 10, false>(blurImage, radius, quality, transposed); } +bool qt_scaleForTransform(const QTransform &transform, qreal *scale); + /*! \internal */ -void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF &srcRect) const +void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF &rect) const { Q_D(const QPixmapBlurFilter); if (!painter->isActive()) return; - if (d->radius <= 0) { + QRectF srcRect = rect; + if (srcRect.isNull()) + srcRect = src.rect(); + + if (d->radius <= 1) { painter->drawPixmap(srcRect.translated(p), src, srcRect); return; } + qreal scaledRadius = radiusScale * d->radius; + qreal scale; + if (qt_scaleForTransform(painter->transform(), &scale)) + scaledRadius /= scale; + QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ? static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0; QPixmapBlurFilter *blurFilter = static_cast<QPixmapBlurFilter*>(filter); if (blurFilter) { - blurFilter->setRadius(d->radius); + blurFilter->setRadius(scaledRadius); blurFilter->setBlurHints(d->hints); blurFilter->draw(painter, p, src, srcRect); return; @@ -693,17 +934,17 @@ void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap QImage srcImage; QImage destImage; - if (srcRect.isNull()) { + if (srcRect == src.rect()) { srcImage = src.toImage(); - destImage = blurred(srcImage, srcImage.rect(), qRound(d->radius)); } else { QRect rect = srcRect.toAlignedRect().intersected(src.rect()); - srcImage = src.copy(rect).toImage(); - destImage = blurred(srcImage, srcImage.rect(), qRound(d->radius)); } - painter->drawImage(p, destImage); + QTransform transform = painter->worldTransform(); + painter->translate(p); + qt_blurImage(painter, srcImage, scaledRadius, (d->hints & QGraphicsBlurEffect::QualityHint), false); + painter->setWorldTransform(transform); } // grayscales the image to dest (could be same). If rect isn't defined @@ -1095,7 +1336,13 @@ void QPixmapDropShadowFilter::draw(QPainter *p, tmpPainter.end(); // blur the alpha channel - tmp = blurred(tmp, tmp.rect(), qRound(d->radius), true); + QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied); + blurred.fill(0); + QPainter blurPainter(&blurred); + qt_blurImage(&blurPainter, tmp, d->radius, false, true); + blurPainter.end(); + + tmp = blurred; // blacken the image... tmpPainter.begin(&tmp); diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 4a450b7..47b5f66 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -70,6 +70,7 @@ QAbstractItemViewPrivate::QAbstractItemViewPrivate() itemDelegate(0), selectionModel(0), ctrlDragSelectionFlag(QItemSelectionModel::NoUpdate), + noSelectionOnMousePress(false), selectionMode(QAbstractItemView::ExtendedSelection), selectionBehavior(QAbstractItemView::SelectItems), currentlyCommittingEditor(0), @@ -1622,6 +1623,7 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event) d->pressedIndex = index; d->pressedModifiers = event->modifiers(); QItemSelectionModel::SelectionFlags command = selectionCommand(index, event); + d->noSelectionOnMousePress = command == QItemSelectionModel::NoUpdate || !index.isValid(); QPoint offset = d->offset(); if ((command & QItemSelectionModel::Current) == 0) d->pressedPosition = pos + offset; @@ -1760,9 +1762,10 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event) d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate; - //in the case the user presses on no item we might decide to clear the selection - if (d->selectionModel && !index.isValid()) - d->selectionModel->select(QModelIndex(), selectionCommand(index, event)); + if (d->selectionModel && d->noSelectionOnMousePress) { + d->noSelectionOnMousePress = false; + d->selectionModel->select(index, selectionCommand(index, event)); + } setState(NoState); diff --git a/src/gui/itemviews/qabstractitemview_p.h b/src/gui/itemviews/qabstractitemview_p.h index 0b5cfbe..7fc6780 100644 --- a/src/gui/itemviews/qabstractitemview_p.h +++ b/src/gui/itemviews/qabstractitemview_p.h @@ -347,6 +347,7 @@ public: QMap<int, QPointer<QAbstractItemDelegate> > columnDelegates; QPointer<QItemSelectionModel> selectionModel; QItemSelectionModel::SelectionFlag ctrlDragSelectionFlag; + bool noSelectionOnMousePress; QAbstractItemView::SelectionMode selectionMode; QAbstractItemView::SelectionBehavior selectionBehavior; diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 9f4cd0c..8c63968 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -4092,9 +4092,15 @@ bool QApplication::notify(QObject *receiver, QEvent *e) bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); touchEvent->setWidget(widget); touchEvent->setAccepted(acceptTouchEvents); + QWeakPointer<QWidget> p = widget; res = acceptTouchEvents && d->notify_helper(widget, touchEvent); eventAccepted = touchEvent->isAccepted(); - widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted); + if (p.isNull()) { + // widget was deleted + widget = 0; + } else { + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted); + } touchEvent->spont = false; if (res && eventAccepted) { // the first widget to accept the TouchBegin gets an implicit grab. @@ -4103,7 +4109,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) d->widgetForTouchPointId[touchPoint.id()] = widget; } break; - } else if (widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { + } else if (p.isNull() || widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { break; } QPoint offset = widget->pos(); diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 1907cca..7dc4d85 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -3654,6 +3654,16 @@ void QWidgetPrivate::setFocus_sys() } } +NSComparisonResult compareViews2Raise(id view1, id view2, void *context) +{ + id topView = reinterpret_cast<id>(context); + if (view1 == topView) + return NSOrderedDescending; + if (view2 == topView) + return NSOrderedAscending; + return NSOrderedSame; +} + void QWidgetPrivate::raise_sys() { Q_Q(QWidget); @@ -3661,7 +3671,6 @@ void QWidgetPrivate::raise_sys() return; #if QT_MAC_USE_COCOA - QMacCocoaAutoReleasePool pool; if (isRealWindow()) { // Calling orderFront shows the window on Cocoa too. if (!q->testAttribute(Qt::WA_DontShowOnScreen) && q->isVisible()) { @@ -3673,16 +3682,9 @@ void QWidgetPrivate::raise_sys() SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly); } } else { - // Cocoa doesn't really have an idea of Z-ordering, but you can - // fake it by changing the order of it. But beware, removing an - // NSView will also remove it as the first responder. So we re-set - // the first responder just in case: NSView *view = qt_mac_nativeview_for(q); NSView *parentView = [view superview]; - NSResponder *firstResponder = [[view window] firstResponder]; - [view removeFromSuperview]; - [parentView addSubview:view]; - [[view window] makeFirstResponder:firstResponder]; + [parentView sortSubviewsUsingFunction:compareViews2Raise context:reinterpret_cast<void *>(view)]; } #else if(q->isWindow()) { @@ -3700,47 +3702,29 @@ void QWidgetPrivate::raise_sys() #endif } +NSComparisonResult compareViews2Lower(id view1, id view2, void *context) +{ + id topView = reinterpret_cast<id>(context); + if (view1 == topView) + return NSOrderedAscending; + if (view2 == topView) + return NSOrderedDescending; + return NSOrderedSame; +} + void QWidgetPrivate::lower_sys() { Q_Q(QWidget); if((q->windowType() == Qt::Desktop)) return; #ifdef QT_MAC_USE_COCOA - QMacCocoaAutoReleasePool pool; if (isRealWindow()) { OSWindowRef window = qt_mac_window_for(q); [window orderBack:window]; } else { - // Cocoa doesn't really have an idea of Z-ordering, but you can - // fake it by changing the order of it. In this case - // we put the item at the beginning of the list, but that means - // we must re-insert everything since we cannot modify the list directly. - NSView *myview = qt_mac_nativeview_for(q); - NSView *parentView = [myview superview]; - NSArray *tmpViews = [parentView subviews]; - NSMutableArray *subviews = [[NSMutableArray alloc] initWithCapacity:[tmpViews count]]; - [subviews addObjectsFromArray:tmpViews]; - NSResponder *firstResponder = [[myview window] firstResponder]; - // Implicit assumption that myViewIndex is included in subviews, that's why I'm not checking - // myViewIndex. - NSUInteger index = 0; - NSUInteger myViewIndex = 0; - bool foundMyView = false; - for (NSView *subview in subviews) { - [subview removeFromSuperview]; - if (subview == myview) { - foundMyView = true; - myViewIndex = index; - } - ++index; - } - [parentView addSubview:myview]; - if (foundMyView) - [subviews removeObjectAtIndex:myViewIndex]; - for (NSView *subview in subviews) - [parentView addSubview:subview]; - [subviews release]; - [[myview window] makeFirstResponder:firstResponder]; + NSView *view = qt_mac_nativeview_for(q); + NSView *parentView = [view superview]; + [parentView sortSubviewsUsingFunction:compareViews2Lower context:reinterpret_cast<void *>(view)]; } #else if(q->isWindow()) { @@ -3753,6 +3737,16 @@ void QWidgetPrivate::lower_sys() #endif } +NSComparisonResult compareViews2StackUnder(id view1, id view2, void *context) +{ + const QHash<NSView *, int> &viewOrder = *reinterpret_cast<QHash<NSView *, int> *>(context); + if (viewOrder[view1] < viewOrder[view2]) + return NSOrderedAscending; + if (viewOrder[view1] > viewOrder[view2]) + return NSOrderedDescending; + return NSOrderedSame; +} + void QWidgetPrivate::stackUnder_sys(QWidget *w) { // stackUnder @@ -3761,37 +3755,23 @@ void QWidgetPrivate::stackUnder_sys(QWidget *w) return; #ifdef QT_MAC_USE_COCOA // Do the same trick as lower_sys() and put this widget before the widget passed in. - QMacCocoaAutoReleasePool pool; - NSView *myview = qt_mac_nativeview_for(q); + NSView *myView = qt_mac_nativeview_for(q); NSView *wView = qt_mac_nativeview_for(w); - NSView *parentView = [myview superview]; - NSArray *tmpViews = [parentView subviews]; - NSMutableArray *subviews = [[NSMutableArray alloc] initWithCapacity:[tmpViews count]]; - [subviews addObjectsFromArray:tmpViews]; - // Implicit assumption that myViewIndex and wViewIndex is included in subviews, - // that's why I'm not checking myViewIndex. - NSUInteger index = 0; - NSUInteger myViewIndex = 0; - NSUInteger wViewIndex = 0; - for (NSView *subview in subviews) { - [subview removeFromSuperview]; - if (subview == myview) - myViewIndex = index; - else if (subview == wView) - wViewIndex = index; - ++index; - } - index = 0; + QHash<NSView *, int> viewOrder; + NSView *parentView = [myView superview]; + NSArray *subviews = [parentView subviews]; + NSUInteger index = 1; + // make a hash of view->zorderindex and make sure z-value is always odd, + // so that when we modify the order we create a new (even) z-value which + // will not interfere with others. for (NSView *subview in subviews) { - if (index == myViewIndex) - continue; - if (index == wViewIndex) - [parentView addSubview:myview]; - [parentView addSubview:subview]; + viewOrder.insert(subview, index * 2); ++index; } - [subviews release]; + viewOrder[myView] = viewOrder[wView] - 1; + + [parentView sortSubviewsUsingFunction:compareViews2StackUnder context:reinterpret_cast<void *>(&viewOrder)]; #else QWidget *p = q->parentWidget(); if(!p || p != w->parentWidget()) diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp index 67dc2c7..e3a6f78 100644 --- a/src/gui/painting/qmemrotate.cpp +++ b/src/gui/painting/qmemrotate.cpp @@ -572,5 +572,26 @@ QT_IMPL_MEMROTATE(quint32, qrgb_generic16) QT_IMPL_MEMROTATE(quint16, qrgb_generic16) #endif +struct qrgb_gl_rgba +{ +public: + inline qrgb_gl_rgba(quint32 v) { + if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) + data = ((v << 16) & 0xff0000) | ((v >> 16) & 0xff) | (v & 0xff00ff00); + else + data = (v << 8) | ((v >> 24) & 0xff); + } + + inline operator quint32() const { return data; } + +private: + quint32 data; +} Q_PACKED; + +void Q_GUI_EXPORT qt_memrotate90_gl(const quint32 *src, int srcWidth, int srcHeight, int srcStride, + quint32 *dest, int dstStride) +{ + qt_memrotate90_template(src, srcWidth, srcHeight, srcStride, reinterpret_cast<qrgb_gl_rgba *>(dest), dstStride); +} QT_END_NAMESPACE diff --git a/src/gui/painting/qmemrotate_p.h b/src/gui/painting/qmemrotate_p.h index 676a880..8aee575 100644 --- a/src/gui/painting/qmemrotate_p.h +++ b/src/gui/painting/qmemrotate_p.h @@ -81,6 +81,8 @@ QT_BEGIN_NAMESPACE void Q_GUI_QWS_EXPORT qt_memrotate180(const srctype*, int, int, int, desttype*, int); \ void Q_GUI_QWS_EXPORT qt_memrotate270(const srctype*, int, int, int, desttype*, int) +void Q_GUI_EXPORT qt_memrotate90(const quint32*, int, int, int, quint32*, int); + QT_DECL_MEMROTATE(quint32, quint32); QT_DECL_MEMROTATE(quint32, quint16); QT_DECL_MEMROTATE(quint16, quint32); diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 33496a9..8ed126f 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -1355,6 +1355,12 @@ void QPainterPrivate::updateState(QPainterState *newState) onto a QGLWidget or by passing \c {-graphicssystem opengl} on the command line when the underlying system supports it. + \o OpenVG - This backend implements the Khronos standard for 2D + and Vector Graphics. It is primarily for embedded devices with + hardware support for OpenVG. The engine can be enabled by + passing \c {-graphicssystem openvg} on the command line when + the underlying system supports it. + \endlist These operations are: diff --git a/src/gui/painting/qprinterinfo_unix.cpp b/src/gui/painting/qprinterinfo_unix.cpp index 6684ff7..930785b 100644 --- a/src/gui/painting/qprinterinfo_unix.cpp +++ b/src/gui/painting/qprinterinfo_unix.cpp @@ -75,7 +75,9 @@ private: QString m_name; bool m_isNull; bool m_default; - QList<QPrinter::PaperSize> m_paperSizes; + mutable bool m_mustGetPaperSizes; + mutable QList<QPrinter::PaperSize> m_paperSizes; + int m_cupsPrinterIndex; QPrinterInfo* q_ptr; }; @@ -838,16 +840,7 @@ QList<QPrinterInfo> QPrinterInfo::availablePrinters() list.append(QPrinterInfo(printerName)); if (cupsPrinters[i].is_default) list[i].d_ptr->m_default = true; - // Find paper sizes. - cups.setCurrentPrinter(i); - const ppd_option_t* sizes = cups.pageSizes(); - if (sizes) { - for (int j = 0; j < sizes->num_choices; ++j) { - list[i].d_ptr->m_paperSizes.append( - QPrinterInfoPrivate::string2PaperSize( - QLatin1String(sizes->choices[j].choice))); - } - } + list[i].d_ptr->m_cupsPrinterIndex = i; } } else { #endif @@ -909,16 +902,7 @@ QPrinterInfo::QPrinterInfo(const QPrinter& printer) if (printerName == printer.printerName()) { if (cupsPrinters[i].is_default) d->m_default = true; - // Find paper sizes. - cups.setCurrentPrinter(i); - const ppd_option_t* sizes = cups.pageSizes(); - if (sizes) { - for (int j = 0; j < sizes->num_choices; ++j) { - d->m_paperSizes.append( - QPrinterInfoPrivate::string2PaperSize( - QLatin1String(sizes->choices[j].choice))); - } - } + d->m_cupsPrinterIndex = i; return; } } @@ -983,6 +967,26 @@ bool QPrinterInfo::isDefault() const QList< QPrinter::PaperSize> QPrinterInfo::supportedPaperSizes() const { const Q_D(QPrinterInfo); + if (d->m_mustGetPaperSizes) { + d->m_mustGetPaperSizes = false; + +#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) + QCUPSSupport cups; + if (QCUPSSupport::isAvailable()) { + // Find paper sizes from CUPS. + cups.setCurrentPrinter(d->m_cupsPrinterIndex); + const ppd_option_t* sizes = cups.pageSizes(); + if (sizes) { + for (int j = 0; j < sizes->num_choices; ++j) { + d->m_paperSizes.append( + QPrinterInfoPrivate::string2PaperSize( + QLatin1String(sizes->choices[j].choice))); + } + } + } +#endif + + } return d->m_paperSizes; } @@ -993,6 +997,8 @@ QPrinterInfoPrivate::QPrinterInfoPrivate() { m_isNull = true; m_default = false; + m_mustGetPaperSizes = true; + m_cupsPrinterIndex = 0; q_ptr = 0; } @@ -1001,6 +1007,8 @@ QPrinterInfoPrivate::QPrinterInfoPrivate(const QString& name) m_name = name; m_isNull = false; m_default = false; + m_mustGetPaperSizes = true; + m_cupsPrinterIndex = 0; q_ptr = 0; } diff --git a/src/gui/styles/qgtkstyle.cpp b/src/gui/styles/qgtkstyle.cpp index afa3325..e10bb41 100644 --- a/src/gui/styles/qgtkstyle.cpp +++ b/src/gui/styles/qgtkstyle.cpp @@ -3375,12 +3375,28 @@ QIcon QGtkStyle::standardIconImplementation(StandardPixmap standardIcon, /*! \reimp */ QRect QGtkStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const { + Q_D(const QGtkStyle); + QRect r = QCleanlooksStyle::subElementRect(element, option, widget); switch (element) { case SE_ProgressBarLabel: case SE_ProgressBarContents: case SE_ProgressBarGroove: return option->rect; + case SE_PushButtonContents: + if (!d->gtk_check_version(2, 10, 0)) { + GtkWidget *gtkButton = d->gtkWidget(QLS("GtkButton")); + GtkBorder *border = 0; + d->gtk_widget_style_get(gtkButton, "inner-border", &border, NULL); + if (border) { + r = option->rect.adjusted(border->left, border->top, -border->right, -border->bottom); + d->gtk_border_free(border); + } else { + r = option->rect.adjusted(1, 1, -1, -1); + } + r = visualRect(option->direction, option->rect, r); + } + break; default: break; } diff --git a/src/gui/styles/qgtkstyle_p.cpp b/src/gui/styles/qgtkstyle_p.cpp index 22dfc62..a644a5b 100644 --- a/src/gui/styles/qgtkstyle_p.cpp +++ b/src/gui/styles/qgtkstyle_p.cpp @@ -158,6 +158,7 @@ Ptr_gtk_window_get_type QGtkStylePrivate::gtk_window_get_type = 0; Ptr_gtk_widget_get_type QGtkStylePrivate::gtk_widget_get_type = 0; Ptr_gtk_rc_get_style_by_paths QGtkStylePrivate::gtk_rc_get_style_by_paths = 0; Ptr_gtk_check_version QGtkStylePrivate::gtk_check_version = 0; +Ptr_gtk_border_free QGtkStylePrivate::gtk_border_free = 0; Ptr_pango_font_description_get_size QGtkStylePrivate::pango_font_description_get_size = 0; Ptr_pango_font_description_get_weight QGtkStylePrivate::pango_font_description_get_weight = 0; @@ -416,6 +417,7 @@ void QGtkStylePrivate::resolveGtk() const gtk_widget_get_type =(Ptr_gtk_widget_get_type)libgtk.resolve("gtk_widget_get_type"); gtk_rc_get_style_by_paths =(Ptr_gtk_rc_get_style_by_paths)libgtk.resolve("gtk_rc_get_style_by_paths"); gtk_check_version =(Ptr_gtk_check_version)libgtk.resolve("gtk_check_version"); + gtk_border_free =(Ptr_gtk_border_free)libgtk.resolve("gtk_border_free"); pango_font_description_get_size = (Ptr_pango_font_description_get_size)libgtk.resolve("pango_font_description_get_size"); pango_font_description_get_weight = (Ptr_pango_font_description_get_weight)libgtk.resolve("pango_font_description_get_weight"); pango_font_description_get_family = (Ptr_pango_font_description_get_family)libgtk.resolve("pango_font_description_get_family"); diff --git a/src/gui/styles/qgtkstyle_p.h b/src/gui/styles/qgtkstyle_p.h index f6ab8a3..c27308f 100644 --- a/src/gui/styles/qgtkstyle_p.h +++ b/src/gui/styles/qgtkstyle_p.h @@ -176,6 +176,7 @@ typedef GtkWidget* (*Ptr_gtk_file_chooser_dialog_new)(const gchar *title, typedef void (*Ptr_gtk_file_chooser_set_current_name) (GtkFileChooser *, const gchar *); typedef gboolean (*Ptr_gtk_file_chooser_set_filename) (GtkFileChooser *chooser, const gchar *name); typedef gint (*Ptr_gtk_dialog_run) (GtkDialog*); +typedef void (*Ptr_gtk_border_free)(GtkBorder *); typedef guchar* (*Ptr_gdk_pixbuf_get_pixels) (const GdkPixbuf *pixbuf); typedef int (*Ptr_gdk_pixbuf_get_width) (const GdkPixbuf *pixbuf); @@ -371,6 +372,7 @@ public: static Ptr_gtk_widget_get_type gtk_widget_get_type; static Ptr_gtk_rc_get_style_by_paths gtk_rc_get_style_by_paths; static Ptr_gtk_check_version gtk_check_version; + static Ptr_gtk_border_free gtk_border_free; static Ptr_pango_font_description_get_size pango_font_description_get_size; static Ptr_pango_font_description_get_weight pango_font_description_get_weight; diff --git a/src/gui/util/qsystemtrayicon.cpp b/src/gui/util/qsystemtrayicon.cpp index c6ea00f..6f2b501 100644 --- a/src/gui/util/qsystemtrayicon.cpp +++ b/src/gui/util/qsystemtrayicon.cpp @@ -380,6 +380,9 @@ bool QSystemTrayIcon::supportsMessages() On Windows, the \a millisecondsTimeoutHint is usually ignored by the system when the application has focus. + On Mac OS X, the Growl notification system must be installed for this function to + display messages. + \sa show() supportsMessages() */ void QSystemTrayIcon::showMessage(const QString& title, const QString& msg, diff --git a/src/gui/util/qsystemtrayicon_mac.mm b/src/gui/util/qsystemtrayicon_mac.mm index b74ca85..93295a7 100644 --- a/src/gui/util/qsystemtrayicon_mac.mm +++ b/src/gui/util/qsystemtrayicon_mac.mm @@ -314,8 +314,22 @@ QT_END_NAMESPACE { Q_UNUSED(notification); down = NO; + + if( ![self icon]->icon().isNull() ) { +#ifndef QT_MAC_USE_COCOA + const short scale = GetMBarHeight()-4; +#else + CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; + const short scale = hgt - 4; +#endif + NSImage *nsimage = static_cast<NSImage *>(qt_mac_create_nsimage([self icon]->icon().pixmap(QSize(scale, scale)))); + [self setImage: nsimage]; + [nsimage release]; + } + if([self icon]->contextMenu()) [self icon]->contextMenu()->hide(); + [self setNeedsDisplay:YES]; } @@ -327,6 +341,20 @@ QT_END_NAMESPACE [self icon]->contextMenu()->hide(); [self setNeedsDisplay:YES]; +#ifndef QT_MAC_USE_COCOA + const short scale = GetMBarHeight()-4; +#else + CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; + const short scale = hgt - 4; +#endif + + if( down && ![self icon]->icon().isNull() ) { + NSImage *nsaltimage = static_cast<NSImage *>(qt_mac_create_nsimage([self icon]->icon().pixmap(QSize(scale, scale), QIcon::Selected))); + [self setImage: nsaltimage]; + [nsaltimage release]; + } + + if (down) [parent triggerSelector:self]; else if ((clickCount%2)) diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index c91c608..923f2e3 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -49,6 +49,9 @@ #include "QtCore/qdatetime.h" #include <ctype.h> +#ifndef QT_NO_DATESTRING +# include <stdio.h> +#endif QT_BEGIN_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h index e319389..e0033be 100644 --- a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h +++ b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h @@ -68,7 +68,7 @@ class Q_OPENGL_EXPORT QGLCustomShaderStage public: QGLCustomShaderStage(); virtual ~QGLCustomShaderStage(); - virtual void setUniforms(QGLShaderProgram*) = 0; + virtual void setUniforms(QGLShaderProgram*) {} void setUniformsDirty(); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 0084476..77ca3a8 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -291,10 +291,7 @@ public: QScopedPointer<QPixmapFilter> convolutionFilter; QScopedPointer<QPixmapFilter> colorizeFilter; QScopedPointer<QPixmapFilter> blurFilter; - QScopedPointer<QPixmapFilter> animationBlurFilter; - QScopedPointer<QPixmapFilter> fastBlurFilter; QScopedPointer<QPixmapFilter> dropShadowFilter; - QScopedPointer<QPixmapFilter> fastDropShadowFilter; QSet<QVectorPath::CacheEntry *> pathCaches; QVector<GLuint> unusedVBOSToClean; diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index b6f8919..2a3ce54 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2063,6 +2063,29 @@ QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G // #define QGL_BIND_TEXTURE_DEBUG +// map from Qt's ARGB endianness-dependent format to GL's big-endian RGBA layout +static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) +{ + const int width = img.width(); + const int height = img.height(); + + if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV + || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) + { + for (int i = 0; i < height; ++i) { + uint *p = (uint *) img.scanLine(i); + for (int x = 0; x < width; ++x) + p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); + } + } else { + for (int i = 0; i < height; ++i) { + uint *p = (uint *) img.scanLine(i); + for (int x = 0; x < width; ++x) + p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff); + } + } +} + QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat, const qint64 key, QGLContext::BindOptions options) { @@ -2215,23 +2238,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G // 32 in the switch above is for the RGB16 case, where we set // the format to GL_RGB Q_ASSERT(img.depth() == 32); - const int width = img.width(); - const int height = img.height(); - - if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV - || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) { - for (int i=0; i < height; ++i) { - uint *p = (uint *) img.scanLine(i); - for (int x=0; x<width; ++x) - p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); - } - } else { - for (int i=0; i < height; ++i) { - uint *p = (uint *) img.scanLine(i); - for (int x=0; x<width; ++x) - p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff); - } - } + qgl_byteSwapImage(img, pixel_type); } #ifdef QT_OPENGL_ES // OpenGL/ES requires that the internal and external formats be identical. diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index c478630..c0a0460 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -55,11 +55,17 @@ #include "qgl_p.h" #include "private/qapplication_p.h" +#include "private/qdrawhelper_p.h" +#include "private/qmemrotate_p.h" #include "private/qmath_p.h" #include "qmath.h" QT_BEGIN_NAMESPACE +// qpixmapfilter.cpp +void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); +QImage qt_halfScaled(const QImage &source); + void QGLPixmapFilterBase::bindTexture(const QPixmap &src) const { const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, QGLContext::BindOptions(QGLContext::DefaultBindOption | QGLContext::MemoryManagedBindOption)); @@ -102,48 +108,21 @@ private: class QGLPixmapBlurFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapBlurFilter> { public: - QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHints hints); - - void setUniforms(QGLShaderProgram *program); - - static QByteArray generateGaussianShader(int radius, bool singlePass = false, bool dropShadow = false); + QGLPixmapBlurFilter(); protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const; - -private: - - mutable QSize m_textureSize; - mutable bool m_horizontalBlur; - mutable bool m_singlePass; - mutable bool m_animatedBlur; - - mutable qreal m_t; - mutable QSize m_targetSize; - - mutable bool m_haveCached; - mutable int m_cachedRadius; - mutable QGraphicsBlurEffect::BlurHints m_hints; }; class QGLPixmapDropShadowFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapDropShadowFilter> { public: - QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHints hints); + QGLPixmapDropShadowFilter(); void setUniforms(QGLShaderProgram *program); protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const; - -private: - mutable QSize m_textureSize; - mutable bool m_horizontalBlur; - mutable bool m_singlePass; - - mutable bool m_haveCached; - mutable int m_cachedRadius; - mutable QGraphicsBlurEffect::BlurHints m_hints; }; extern QGLWidget *qt_gl_share_widget(); @@ -158,31 +137,14 @@ QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *pr return d->colorizeFilter.data(); case QPixmapFilter::BlurFilter: { - const QPixmapBlurFilter *proto = static_cast<const QPixmapBlurFilter *>(prototype); - if (proto->blurHints() & QGraphicsBlurEffect::AnimationHint) { - if (!d->animationBlurFilter) - d->animationBlurFilter.reset(new QGLPixmapBlurFilter(proto->blurHints())); - return d->animationBlurFilter.data(); - } - if ((proto->blurHints() & QGraphicsBlurEffect::QualityHint) && proto->radius() > 5) { - if (!d->blurFilter) - d->blurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::QualityHint)); - return d->blurFilter.data(); - } - if (!d->fastBlurFilter) - d->fastBlurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::PerformanceHint)); - return d->fastBlurFilter.data(); + if (!d->blurFilter) + d->blurFilter.reset(new QGLPixmapBlurFilter()); + return d->blurFilter.data(); } case QPixmapFilter::DropShadowFilter: { - const QPixmapDropShadowFilter *proto = static_cast<const QPixmapDropShadowFilter *>(prototype); - if (proto->blurRadius() <= 5) { - if (!d->fastDropShadowFilter) - d->fastDropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::PerformanceHint)); - return d->fastDropShadowFilter.data(); - } if (!d->dropShadowFilter) - d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::QualityHint)); + d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter()); return d->dropShadowFilter.data(); } @@ -311,59 +273,43 @@ bool QGLPixmapConvolutionFilter::processGL(QPainter *painter, const QPointF &pos return true; } -static const char *qt_gl_texture_sampling_helper = - "lowp float texture2DAlpha(lowp sampler2D src, highp vec2 srcCoords) {\n" - " return texture2D(src, srcCoords).a;\n" - "}\n"; - -QGLPixmapBlurFilter::QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHints hints) - : m_animatedBlur(false) - , m_haveCached(false) - , m_cachedRadius(0) - , m_hints(hints) -{ -} - -// should be even numbers as they will be divided by two -static const int qCachedBlurLevels[] = { 6, 14, 30 }; -static const int qNumCachedBlurTextures = sizeof(qCachedBlurLevels) / sizeof(*qCachedBlurLevels); -static const int qMaxCachedBlurLevel = qCachedBlurLevels[qNumCachedBlurTextures - 1]; - -static qreal qLogBlurLevel(int level) +QGLPixmapBlurFilter::QGLPixmapBlurFilter() { - static bool initialized = false; - static qreal logBlurLevelCache[qNumCachedBlurTextures]; - if (!initialized) { - for (int i = 0; i < qNumCachedBlurTextures; ++i) - logBlurLevelCache[i] = qLn(qCachedBlurLevels[i]); - initialized = true; - } - return logBlurLevelCache[level]; } class QGLBlurTextureInfo { public: - QGLBlurTextureInfo(QSize size, GLuint textureIds[]) - : m_size(size) + QGLBlurTextureInfo(const QImage &image, GLuint tex, qreal r) + : m_texture(tex) + , m_radius(r) { - for (int i = 0; i < qNumCachedBlurTextures; ++i) - m_textureIds[i] = textureIds[i]; + m_paddedImage << image; } ~QGLBlurTextureInfo() { - glDeleteTextures(qNumCachedBlurTextures, m_textureIds); + glDeleteTextures(1, &m_texture); } - QSize size() const { return m_size; } - GLuint textureId(int i) const { return m_textureIds[i]; } + QImage paddedImage(int scaleLevel = 0) const; + GLuint texture() const { return m_texture; } + qreal radius() const { return m_radius; } private: - GLuint m_textureIds[qNumCachedBlurTextures]; - QSize m_size; + mutable QList<QImage> m_paddedImage; + GLuint m_texture; + qreal m_radius; }; +QImage QGLBlurTextureInfo::paddedImage(int scaleLevel) const +{ + for (int i = m_paddedImage.size() - 1; i <= scaleLevel; ++i) + m_paddedImage << qt_halfScaled(m_paddedImage.at(i)); + + return m_paddedImage.at(scaleLevel); +} + class QGLBlurTextureCache : public QObject { public: @@ -373,7 +319,6 @@ public: ~QGLBlurTextureCache(); QGLBlurTextureInfo *takeBlurTextureInfo(const QPixmap &pixmap); - bool fitsInCache(const QPixmap &pixmap) const; bool hasBlurTextureInfo(const QPixmap &pixmap) const; void insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info); void clearBlurTextureInfo(const QPixmap &pixmap); @@ -458,12 +403,7 @@ void QGLBlurTextureCache::insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTe if (timerId) killTimer(timerId); - timerId = startTimer(1000); -} - -bool QGLBlurTextureCache::fitsInCache(const QPixmap &pixmap) const -{ - return pixmap.width() * pixmap.height() <= cache.maxCost(); + timerId = startTimer(8000); } void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap) @@ -474,567 +414,219 @@ void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap) } } -static const char *qt_gl_interpolate_filter = - "uniform lowp float interpolationValue;" - "uniform lowp sampler2D interpolateTarget;" - "uniform highp vec4 interpolateMapping;" - "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)" - "{" - " return mix(texture2D(interpolateTarget, interpolateMapping.xy + interpolateMapping.zw * srcCoords)," - " texture2D(src, srcCoords), interpolationValue);" - "}"; +static const int qAnimatedBlurLevelIncrement = 16; +static const int qMaxBlurHalfScaleLevel = 1; -static void initializeTexture(GLuint id, int width, int height) +static GLuint generateBlurTexture(const QSize &size, GLenum format = GL_RGBA) { - glBindTexture(GL_TEXTURE_2D, id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glBindTexture(GL_TEXTURE_2D, 0); + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, + GL_UNSIGNED_BYTE, 0); + return texture; } -bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const +static inline uint nextMultiple(uint x, uint multiplier) { - QGLPixmapBlurFilter *filter = const_cast<QGLPixmapBlurFilter *>(this); - - QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); - QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx); - - if ((m_hints & QGraphicsBlurEffect::AnimationHint) && blurTextureCache->fitsInCache(src)) { - QRect targetRect = src.rect().adjusted(-qMaxCachedBlurLevel, -qMaxCachedBlurLevel, qMaxCachedBlurLevel, qMaxCachedBlurLevel); - // ensure even dimensions (going to divide by two) - targetRect.setWidth((targetRect.width() + 1) & ~1); - targetRect.setHeight((targetRect.height() + 1) & ~1); - - QGLBlurTextureInfo *info = 0; - if (blurTextureCache->hasBlurTextureInfo(src)) { - info = blurTextureCache->takeBlurTextureInfo(src); - } else { - m_animatedBlur = false; - m_hints = QGraphicsBlurEffect::QualityHint; - m_singlePass = false; - - QGLFramebufferObjectFormat format; - format.setInternalTextureFormat(GLenum(GL_RGBA)); - QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size() / 2, format, true); - - if (!fbo) - return false; - - QPainter fboPainter(fbo); - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(fboPainter.paintEngine()); - - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - // ensure GL_LINEAR filtering is used for scaling down to half the size - fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); - fboPainter.setCompositionMode(QPainter::CompositionMode_Source); - fboPainter.drawPixmap(qMaxCachedBlurLevel / 2, qMaxCachedBlurLevel / 2, - targetRect.width() / 2 - qMaxCachedBlurLevel, targetRect.height() / 2 - qMaxCachedBlurLevel, src); - - GLuint textures[qNumCachedBlurTextures]; // blur textures - glGenTextures(qNumCachedBlurTextures, textures); - GLuint temp; // temp texture - glGenTextures(1, &temp); - - initializeTexture(temp, fbo->width(), fbo->height()); - m_textureSize = fbo->size(); - - int currentBlur = 0; - - QRect fboRect(0, 0, fbo->width(), fbo->height()); - GLuint sourceTexture = fbo->texture(); - for (int i = 0; i < qNumCachedBlurTextures; ++i) { - int targetBlur = qCachedBlurLevels[i] / 2; - - int blurDelta = qRound(qSqrt(targetBlur * targetBlur - currentBlur * currentBlur)); - QByteArray source = generateGaussianShader(blurDelta); - filter->setSource(source); - - currentBlur = targetBlur; - - // now we're going to be nasty and keep using the same FBO with different textures - glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, temp, 0); - - m_horizontalBlur = true; - filter->setOnPainter(&fboPainter); - engine->drawTexture(fboRect, sourceTexture, fbo->size(), fboRect); - filter->removeFromPainter(&fboPainter); - - sourceTexture = textures[i]; - initializeTexture(sourceTexture, fbo->width(), fbo->height()); - - glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, textures[i], 0); - - m_horizontalBlur = false; - filter->setOnPainter(&fboPainter); - engine->drawTexture(fboRect, temp, fbo->size(), fboRect); - filter->removeFromPainter(&fboPainter); - } + uint mod = x % multiplier; + if (mod == 0) + return x; + return x + multiplier - mod; +} - glDeleteTextures(1, &temp); +void qt_memrotate90_gl(const quint32 *src, int srcWidth, int srcHeight, int srcStride, + quint32 *dest, int dstStride); - // reattach the original FBO texture - glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, fbo->texture(), 0); +bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const +{ + if (radius() < 1) { + painter->drawPixmap(pos, src); + return true; + } - fboPainter.end(); + qreal actualRadius = radius(); - qgl_fbo_pool()->release(fbo); + QGLPixmapBlurFilter *filter = const_cast<QGLPixmapBlurFilter *>(this); - info = new QGLBlurTextureInfo(fboRect.size(), textures); - } + QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); - if (!m_haveCached || !m_animatedBlur) { - m_haveCached = true; - m_animatedBlur = true; - m_hints = QGraphicsBlurEffect::AnimationHint; - filter->setSource(qt_gl_interpolate_filter); - } + QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx); + QGLBlurTextureInfo *info = 0; + int padding = nextMultiple(qCeil(actualRadius), qAnimatedBlurLevelIncrement); + QRect targetRect = src.rect().adjusted(-padding, -padding, padding, padding); - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); + // pad so that we'll be able to half-scale qMaxBlurHalfScaleLevel times + targetRect.setWidth((targetRect.width() + (qMaxBlurHalfScaleLevel-1)) & ~(qMaxBlurHalfScaleLevel-1)); + targetRect.setHeight((targetRect.height() + (qMaxBlurHalfScaleLevel-1)) & ~(qMaxBlurHalfScaleLevel-1)); - qreal logRadius = qLn(radius()); + QSize textureSize; - int t; - for (t = -1; t < qNumCachedBlurTextures - 2; ++t) { - if (logRadius < qLogBlurLevel(t+1)) - break; - } + info = blurTextureCache->takeBlurTextureInfo(src); + if (!info || info->radius() < actualRadius) { + QSize paddedSize = targetRect.size() / 2; - qreal logBase = t >= 0 ? qLogBlurLevel(t) : 0; - m_t = qBound(qreal(0), (logRadius - logBase) / (qLogBlurLevel(t+1) - logBase), qreal(1)); + QImage padded(paddedSize.height(), paddedSize.width(), QImage::Format_ARGB32_Premultiplied); + padded.fill(0); - m_textureSize = info->size(); + if (info) { + int oldPadding = qRound(info->radius()); - glActiveTexture(GL_TEXTURE0 + 3); - if (t >= 0) { - glBindTexture(GL_TEXTURE_2D, info->textureId(t)); - m_targetSize = info->size(); + QPainter p(&padded); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.drawImage((padding - oldPadding) / 2, (padding - oldPadding) / 2, info->paddedImage()); + p.end(); } else { - QGLTexture *texture = - ctx->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, - QGLContext::InternalBindOption - | QGLContext::CanFlipNativePixmapBindOption); - m_targetSize = src.size(); - if (!(texture->options & QGLContext::InvertedYBindOption)) - m_targetSize.setHeight(-m_targetSize.height()); + // TODO: combine byteswapping and memrotating into one by declaring + // custom GL_RGBA pixel type and qt_colorConvert template for it + QImage prepadded = qt_halfScaled(src.toImage()).convertToFormat(QImage::Format_ARGB32_Premultiplied); + + // byte-swap and memrotates in one go + qt_memrotate90_gl(reinterpret_cast<const quint32*>(prepadded.bits()), + prepadded.width(), prepadded.height(), prepadded.bytesPerLine(), + reinterpret_cast<quint32*>(padded.scanLine(padding / 2)) + padding / 2, + padded.bytesPerLine()); } - // restrict the target rect to the max of the radii we are interpolating between - int radiusDelta = qMaxCachedBlurLevel - qCachedBlurLevels[t+1]; - targetRect = targetRect.translated(pos.toPoint()).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta); - - radiusDelta /= 2; - QRect sourceRect = QRect(QPoint(), m_textureSize).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta); - - engine->drawTexture(targetRect, info->textureId(t+1), m_textureSize, sourceRect); + delete info; + info = new QGLBlurTextureInfo(padded, generateBlurTexture(paddedSize), padding); - glActiveTexture(GL_TEXTURE0 + 3); - glBindTexture(GL_TEXTURE_2D, 0); - - filter->removeFromPainter(painter); - blurTextureCache->insertBlurTextureInfo(src, info); - - return true; - } - - if (blurTextureCache->hasBlurTextureInfo(src)) - blurTextureCache->clearBlurTextureInfo(src); - - int actualRadius = qRound(radius()); - int filterRadius = actualRadius; - int fastRadii[] = { 1, 2, 3, 5, 8, 15, 25 }; - if (!(m_hints & QGraphicsBlurEffect::QualityHint)) { - uint i = 0; - for (; i < (sizeof(fastRadii)/sizeof(*fastRadii))-1; ++i) { - if (fastRadii[i+1] > filterRadius) - break; - } - filterRadius = fastRadii[i]; + textureSize = paddedSize; + } else { + textureSize = QSize(info->paddedImage().height(), info->paddedImage().width()); } - m_singlePass = filterRadius <= 3; - - if (!m_haveCached || m_animatedBlur || filterRadius != m_cachedRadius) { - // Only regenerate the shader from source if parameters have changed. - m_haveCached = true; - m_animatedBlur = false; - m_cachedRadius = filterRadius; - QByteArray source = generateGaussianShader(filterRadius, m_singlePass); - filter->setSource(source); + actualRadius *= qreal(0.5); + int level = 1; + for (; level < qMaxBlurHalfScaleLevel; ++level) { + if (actualRadius <= 16) + break; + actualRadius *= qreal(0.5); } - QRect targetRect = QRectF(src.rect()).translated(pos).adjusted(-actualRadius, -actualRadius, actualRadius, actualRadius).toAlignedRect(); + const int s = (1 << level); - if (m_singlePass) { - // prepare for updateUniforms - m_textureSize = src.size(); + int prepadding = qRound(info->radius()); + padding = qMin(prepadding, qCeil(actualRadius) << level); + targetRect = src.rect().adjusted(-padding, -padding, padding, padding); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(pos.x(), pos.y())); - painter->fillRect(targetRect, pixmapBrush); - filter->removeFromPainter(painter); - } else { - QGLFramebufferObjectFormat format; - format.setInternalTextureFormat(GLenum(src.hasAlphaChannel() ? GL_RGBA : GL_RGB)); - QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size(), format); + targetRect.setWidth(targetRect.width() & ~(s-1)); + targetRect.setHeight(targetRect.height() & ~(s-1)); - if (!fbo) - return false; + int paddingDelta = (prepadding - padding) >> level; - // prepare for updateUniforms - m_textureSize = src.size(); + QRect subRect(paddingDelta, paddingDelta, targetRect.width() >> level, targetRect.height() >> level); + QImage sourceImage = info->paddedImage(level-1); - // horizontal pass, to pixmap - m_horizontalBlur = true; + QImage subImage(subRect.height(), subRect.width(), QImage::Format_ARGB32_Premultiplied); + qt_rectcopy((QRgb *)subImage.bits(), ((QRgb *)sourceImage.scanLine(paddingDelta)) + paddingDelta, + 0, 0, subRect.height(), subRect.width(), subImage.bytesPerLine(), sourceImage.bytesPerLine()); - QPainter fboPainter(fbo); + GLuint texture = info->texture(); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); + qt_blurImage(subImage, actualRadius, blurHints() & QGraphicsBlurEffect::QualityHint, 1); - // ensure GL_LINEAR filtering is used - fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); - fboPainter.setCompositionMode(QPainter::CompositionMode_Source); - filter->setOnPainter(&fboPainter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius)); - fboPainter.fillRect(QRect(0, 0, targetRect.width(), targetRect.height()), pixmapBrush); - filter->removeFromPainter(&fboPainter); - fboPainter.end(); + // subtract one pixel off the end to prevent the bilinear sampling from sampling uninitialized data + QRect textureSubRect = subImage.rect().adjusted(0, 0, -1, -1); + QRectF targetRectF = QRectF(targetRect).adjusted(0, 0, -targetRect.width() / qreal(textureSize.width()), -targetRect.height() / qreal(textureSize.height())); - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + glBindTexture(GL_TEXTURE_2D, texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subImage.width(), subImage.height(), GL_RGBA, + GL_UNSIGNED_BYTE, const_cast<const QImage &>(subImage).bits()); - // vertical pass, to painter - m_horizontalBlur = false; - m_textureSize = fbo->size(); + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + painter->setRenderHint(QPainter::SmoothPixmapTransform); - painter->save(); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - engine->drawTexture(targetRect, fbo->texture(), fbo->size(), QRect(QPoint(), targetRect.size()).translated(0, fbo->height() - targetRect.height())); - filter->removeFromPainter(painter); - painter->restore(); + // texture is flipped on the y-axis + targetRectF = QRectF(targetRectF.x(), targetRectF.bottom(), targetRectF.width(), -targetRectF.height()); + engine->drawTexture(targetRectF.translated(pos), texture, textureSize, textureSubRect); - qgl_fbo_pool()->release(fbo); - } + blurTextureCache->insertBlurTextureInfo(src, info); return true; } -void QGLPixmapBlurFilter::setUniforms(QGLShaderProgram *program) -{ - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - if (m_animatedBlur) { - program->setUniformValue("interpolateTarget", 3); - program->setUniformValue("interpolationValue", GLfloat(m_t)); - - if (m_textureSize == m_targetSize) { - program->setUniformValue("interpolateMapping", 0.0f, 0.0f, 1.0f, 1.0f); - } else { - float offsetX = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.width()); - float offsetY = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.height()); - - if (m_targetSize.height() < 0) - offsetY = 1 + offsetY; - - float scaleX = 2.0f * qreal(m_textureSize.width()) / qreal(m_targetSize.width()); - float scaleY = 2.0f * qreal(m_textureSize.height()) / qreal(m_targetSize.height()); - - program->setUniformValue("interpolateMapping", offsetX, offsetY, scaleX, scaleY); - } - - return; - } +static const char *qt_gl_drop_shadow_filter = + "uniform lowp vec4 shadowColor;" + "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)" + "{" + " return shadowColor * texture2D(src, srcCoords.yx).a;" + "}"; - if (m_hints & QGraphicsBlurEffect::QualityHint) { - if (m_singlePass) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, 1.0 / m_textureSize.height()); - } else { - qreal blur = radius() / qreal(m_cachedRadius); - - if (m_singlePass) - program->setUniformValue("delta", blur / m_textureSize.width(), blur / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", blur / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, blur / m_textureSize.height()); - } -} -static inline qreal gaussian(qreal dx, qreal sigma) +QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter() { - return exp(-dx * dx / (2 * sigma * sigma)) / (Q_2PI * sigma * sigma); + setSource(qt_gl_drop_shadow_filter); } -QByteArray QGLPixmapBlurFilter::generateGaussianShader(int radius, bool singlePass, bool dropShadow) +bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const { - Q_ASSERT(radius >= 1); - - radius = qMin(127, radius); - - static QCache<uint, QByteArray> shaderSourceCache; - uint key = radius | (int(singlePass) << 7) | (int(dropShadow) << 8); - QByteArray *cached = shaderSourceCache.object(key); - if (cached) - return *cached; - - QByteArray source; - source.reserve(1000); - source.append(qt_gl_texture_sampling_helper); - - source.append("uniform highp vec2 delta;\n"); - if (dropShadow) - source.append("uniform mediump vec4 shadowColor;\n"); - source.append("lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords) {\n"); - - QVector<qreal> sampleOffsets; - QVector<qreal> weights; - - QVector<qreal> gaussianComponents; - - qreal sigma = radius / 1.65; - - qreal sum = 0; - for (int i = -radius; i < radius; ++i) { - float value = gaussian(i, sigma); - gaussianComponents << value; - sum += value; - } - - // normalize - for (int i = 0; i < gaussianComponents.size(); ++i) - gaussianComponents[i] /= sum; - - for (int i = 0; i < gaussianComponents.size() - 1; i += 2) { - qreal weight = gaussianComponents.at(i) + gaussianComponents.at(i + 1); - qreal offset = i - radius + gaussianComponents.at(i + 1) / weight; - - sampleOffsets << offset; - weights << weight; - } - - int limit = sampleOffsets.size(); - if (singlePass) - limit *= limit; - - QByteArray baseCoordinate = "srcCoords"; - - for (int i = 0; i < limit; ++i) { - QByteArray coordinate = baseCoordinate; - - qreal weight; - if (singlePass) { - const int xIndex = i % sampleOffsets.size(); - const int yIndex = i / sampleOffsets.size(); - - const qreal deltaX = sampleOffsets.at(xIndex); - const qreal deltaY = sampleOffsets.at(yIndex); - weight = weights.at(xIndex) * weights.at(yIndex); - - if (!qFuzzyCompare(deltaX, deltaY)) { - coordinate.append(" + vec2(delta.x * float("); - coordinate.append(QByteArray::number(deltaX)); - coordinate.append("), delta.y * float("); - coordinate.append(QByteArray::number(deltaY)); - coordinate.append("))"); - } else if (!qFuzzyIsNull(deltaX)) { - coordinate.append(" + delta * float("); - coordinate.append(QByteArray::number(deltaX)); - coordinate.append(")"); - } - } else { - const qreal delta = sampleOffsets.at(i); - weight = weights.at(i); - if (!qFuzzyIsNull(delta)) { - coordinate.append(" + delta * float("); - coordinate.append(QByteArray::number(delta)); - coordinate.append(")"); - } - } - - if (i == 0) { - if (dropShadow) - source.append(" mediump float sample = "); - else - source.append(" mediump vec4 sample = "); - } else { - if (dropShadow) - source.append(" sample += "); - else - source.append(" sample += "); - } + QGLPixmapDropShadowFilter *filter = const_cast<QGLPixmapDropShadowFilter *>(this); - source.append("texture2D(src, "); - source.append(coordinate); - source.append(")"); + qreal r = blurRadius(); + QRectF targetRectUnaligned = QRectF(src.rect()).translated(pos + offset()).adjusted(-r, -r, r, r); + QRect targetRect = targetRectUnaligned.toAlignedRect(); - if (dropShadow) - source.append(".a"); + // ensure even dimensions (going to divide by two) + targetRect.setWidth((targetRect.width() + 1) & ~1); + targetRect.setHeight((targetRect.height() + 1) & ~1); - if (!qFuzzyCompare(weight, qreal(1))) { - source.append(" * float("); - source.append(QByteArray::number(weight)); - source.append(");\n"); - } else { - source.append(";\n"); - } - } + QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); + QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx); - source.append(" return "); - if (dropShadow) - source.append("shadowColor * "); - source.append("sample;\n"); - source.append("}\n"); + QGLBlurTextureInfo *info = blurTextureCache->takeBlurTextureInfo(src); + if (!info || info->radius() != r) { + QImage half = qt_halfScaled(src.toImage().alphaChannel()); - cached = new QByteArray(source); - shaderSourceCache.insert(key, cached); + qreal rx = r + targetRect.left() - targetRectUnaligned.left(); + qreal ry = r + targetRect.top() - targetRectUnaligned.top(); - return source; -} + QImage image = QImage(targetRect.size() / 2, QImage::Format_Indexed8); + image.setColorTable(half.colorTable()); + image.fill(0); + int dx = qRound(rx * qreal(0.5)); + int dy = qRound(ry * qreal(0.5)); + qt_rectcopy(image.bits(), half.bits(), dx, dy, + half.width(), half.height(), + image.bytesPerLine(), half.bytesPerLine()); -QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHints hints) - : m_haveCached(false) - , m_cachedRadius(0) - , m_hints(hints) -{ -} + qt_blurImage(image, r * qreal(0.5), false, 1); -bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const -{ - QGLPixmapDropShadowFilter *filter = const_cast<QGLPixmapDropShadowFilter *>(this); + GLuint texture = generateBlurTexture(image.size(), GL_ALPHA); - int actualRadius = qRound(blurRadius()); - int filterRadius = actualRadius; - m_singlePass = filterRadius <= 3; + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image.width(), image.height(), GL_ALPHA, + GL_UNSIGNED_BYTE, image.bits()); - if (!m_haveCached || filterRadius != m_cachedRadius) { - // Only regenerate the shader from source if parameters have changed. - m_haveCached = true; - m_cachedRadius = filterRadius; - QByteArray source = QGLPixmapBlurFilter::generateGaussianShader(filterRadius, m_singlePass, true); - filter->setSource(source); + info = new QGLBlurTextureInfo(image, texture, r); } - QRect targetRect = QRectF(src.rect()).translated(pos + offset()).adjusted(-actualRadius, -actualRadius, actualRadius, actualRadius).toAlignedRect(); - - if (m_singlePass) { - // prepare for updateUniforms - m_textureSize = src.size(); - - painter->save(); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(pos.x() + offset().x(), pos.y() + offset().y())); - painter->fillRect(targetRect, pixmapBrush); - filter->removeFromPainter(painter); - painter->restore(); - } else { - QGLFramebufferObjectFormat format; - format.setInternalTextureFormat(GLenum(src.hasAlphaChannel() ? GL_RGBA : GL_RGB)); - QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size(), format); - - if (!fbo) - return false; - - // prepare for updateUniforms - m_textureSize = src.size(); - - // horizontal pass, to pixmap - m_horizontalBlur = true; - - QPainter fboPainter(fbo); + GLuint texture = info->texture(); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - // ensure GL_LINEAR filtering is used - fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); - fboPainter.setCompositionMode(QPainter::CompositionMode_Source); - filter->setOnPainter(&fboPainter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius)); - fboPainter.fillRect(QRect(0, 0, targetRect.width(), targetRect.height()), pixmapBrush); - filter->removeFromPainter(&fboPainter); - fboPainter.end(); - - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + filter->setOnPainter(painter); - // vertical pass, to painter - m_horizontalBlur = false; - m_textureSize = fbo->size(); + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + painter->setRenderHint(QPainter::SmoothPixmapTransform); - painter->save(); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - engine->drawTexture(targetRect, fbo->texture(), fbo->size(), QRectF(0, fbo->height() - targetRect.height(), targetRect.width(), targetRect.height())); - filter->removeFromPainter(painter); - painter->restore(); + engine->drawTexture(targetRect, texture, info->paddedImage().size(), info->paddedImage().rect()); - qgl_fbo_pool()->release(fbo); - } + filter->removeFromPainter(painter); // Now draw the actual pixmap over the top. painter->drawPixmap(pos, src, srcRect); + blurTextureCache->insertBlurTextureInfo(src, info); + return true; } void QGLPixmapDropShadowFilter::setUniforms(QGLShaderProgram *program) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - QColor col = color(); - if (m_horizontalBlur && !m_singlePass) { - program->setUniformValue("shadowColor", 1.0f, 1.0f, 1.0f, 1.0f); - } else { - qreal alpha = col.alphaF(); - program->setUniformValue("shadowColor", col.redF() * alpha, - col.greenF() * alpha, - col.blueF() * alpha, - alpha); - } - - if (m_hints & QGraphicsBlurEffect::QualityHint) { - if (m_singlePass) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, 1.0 / m_textureSize.height()); - } else { - qreal blur = blurRadius() / qreal(m_cachedRadius); - - if (m_singlePass) - program->setUniformValue("delta", blur / m_textureSize.width(), blur / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", blur / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, blur / m_textureSize.height()); - } + qreal alpha = col.alphaF(); + program->setUniformValue("shadowColor", col.redF() * alpha, + col.greenF() * alpha, + col.blueF() * alpha, + alpha); } QT_END_NAMESPACE diff --git a/src/openvg/openvg.pro b/src/openvg/openvg.pro index 8927c4c..c8c9917 100644 --- a/src/openvg/openvg.pro +++ b/src/openvg/openvg.pro @@ -16,11 +16,13 @@ HEADERS += \ qpaintengine_vg_p.h \ qpixmapdata_vg_p.h \ qpixmapfilter_vg_p.h \ - qvgcompositionhelper_p.h + qvgcompositionhelper_p.h \ + qvgimagepool_p.h SOURCES += \ qpaintengine_vg.cpp \ qpixmapdata_vg.cpp \ - qpixmapfilter_vg.cpp + qpixmapfilter_vg.cpp \ + qvgimagepool.cpp contains(QT_CONFIG, egl) { HEADERS += \ diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index 6b829dd..04fee08 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -43,6 +43,7 @@ #include "qpixmapdata_vg_p.h" #include "qpixmapfilter_vg_p.h" #include "qvgcompositionhelper_p.h" +#include "qvgimagepool_p.h" #if !defined(QT_NO_EGL) #include <QtGui/private/qegl_p.h> #include "qwindowsurface_vgegl_p.h" @@ -1018,7 +1019,7 @@ static VGImage toVGImage const uchar *pixels = img.bits(); - VGImage vgImg = vgCreateImage + VGImage vgImg = QVGImagePool::instance()->createPermanentImage (format, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); vgImageSubData (vgImg, pixels, img.bytesPerLine(), format, 0, 0, @@ -1063,7 +1064,7 @@ static VGImage toVGImageSubRect const uchar *pixels = img.bits() + bpp * sr.x() + img.bytesPerLine() * sr.y(); - VGImage vgImg = vgCreateImage + VGImage vgImg = QVGImagePool::instance()->createPermanentImage (format, sr.width(), sr.height(), VG_IMAGE_QUALITY_FASTER); vgImageSubData (vgImg, pixels, img.bytesPerLine(), format, 0, 0, @@ -1084,7 +1085,7 @@ static VGImage toVGImageWithOpacity(const QImage & image, qreal opacity) const uchar *pixels = img.bits(); - VGImage vgImg = vgCreateImage + VGImage vgImg = QVGImagePool::instance()->createPermanentImage (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); vgImageSubData (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, @@ -1106,7 +1107,7 @@ static VGImage toVGImageWithOpacitySubRect const uchar *pixels = img.bits(); - VGImage vgImg = vgCreateImage + VGImage vgImg = QVGImagePool::instance()->createPermanentImage (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); vgImageSubData (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, @@ -1194,6 +1195,12 @@ VGPaintType QVGPaintEnginePrivate::setBrush if (pd->classId() == QPixmapData::OpenVGClass) { QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd); vgImg = vgpd->toVGImage(); + + // We don't want the pool to reclaim this image + // because we cannot predict when the paint object + // will stop using it. Replacing the image with + // new data will make the paint object invalid. + vgpd->detachImageFromPool(); } else { vgImg = toVGImage(*(pd->buffer())); deref = true; @@ -1201,6 +1208,7 @@ VGPaintType QVGPaintEnginePrivate::setBrush } else if (pd->classId() == QPixmapData::OpenVGClass) { QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd); vgImg = vgpd->toVGImage(opacity); + vgpd->detachImageFromPool(); } else { vgImg = toVGImageWithOpacity(*(pd->buffer()), opacity); deref = true; diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index af6f0f0..358ec4d 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -43,6 +43,7 @@ #include "qpaintengine_vg_p.h" #include <QtGui/private/qdrawhelper_p.h> #include "qvg_p.h" +#include "qvgimagepool_p.h" #ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE #include <graphics/sgimage.h> @@ -63,6 +64,8 @@ QVGPixmapData::QVGPixmapData(PixelType type) vgImageOpacity = VG_INVALID_HANDLE; cachedOpacity = 1.0f; recreate = true; + inImagePool = false; + inLRU = false; #if !defined(QT_NO_EGL) context = 0; qt_vg_register_pixmap(this); @@ -78,32 +81,43 @@ QVGPixmapData::~QVGPixmapData() #endif } +void QVGPixmapData::destroyImages() +{ + if (inImagePool) { + QVGImagePool *pool = QVGImagePool::instance(); + if (vgImage != VG_INVALID_HANDLE) + pool->releaseImage(this, vgImage); + if (vgImageOpacity != VG_INVALID_HANDLE) + pool->releaseImage(this, vgImageOpacity); + } else { + if (vgImage != VG_INVALID_HANDLE) + vgDestroyImage(vgImage); + if (vgImageOpacity != VG_INVALID_HANDLE) + vgDestroyImage(vgImageOpacity); + } + vgImage = VG_INVALID_HANDLE; + vgImageOpacity = VG_INVALID_HANDLE; + inImagePool = false; +} + void QVGPixmapData::destroyImageAndContext() { if (vgImage != VG_INVALID_HANDLE) { // We need to have a context current to destroy the image. #if !defined(QT_NO_EGL) if (context->isCurrent()) { - vgDestroyImage(vgImage); - if (vgImageOpacity != VG_INVALID_HANDLE) - vgDestroyImage(vgImageOpacity); + destroyImages(); } else { // We don't currently have a widget surface active, but we // need a surface to make the context current. So use the // shared pbuffer surface instead. context->makeCurrent(qt_vg_shared_surface()); - vgDestroyImage(vgImage); - if (vgImageOpacity != VG_INVALID_HANDLE) - vgDestroyImage(vgImageOpacity); + destroyImages(); context->lazyDoneCurrent(); } #else - vgDestroyImage(vgImage); - if (vgImageOpacity != VG_INVALID_HANDLE) - vgDestroyImage(vgImageOpacity); + destroyImages(); #endif - vgImage = VG_INVALID_HANDLE; - vgImageOpacity = VG_INVALID_HANDLE; } #if !defined(QT_NO_EGL) if (context) { @@ -234,26 +248,22 @@ VGImage QVGPixmapData::toVGImage() context = qt_vg_create_context(0, QInternal::Pixmap); #endif - if (recreate && prevSize != QSize(w, h)) { - if (vgImage != VG_INVALID_HANDLE) { - vgDestroyImage(vgImage); - vgImage = VG_INVALID_HANDLE; - } - if (vgImageOpacity != VG_INVALID_HANDLE) { - vgDestroyImage(vgImageOpacity); - vgImageOpacity = VG_INVALID_HANDLE; - } - } else if (recreate) { + if (recreate && prevSize != QSize(w, h)) + destroyImages(); + else if (recreate) cachedOpacity = -1.0f; // Force opacity image to be refreshed later. - } if (vgImage == VG_INVALID_HANDLE) { - vgImage = vgCreateImage - (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + vgImage = QVGImagePool::instance()->createImageForPixmap + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this); // Bail out if we run out of GPU memory - try again next time. if (vgImage == VG_INVALID_HANDLE) return VG_INVALID_HANDLE; + + inImagePool = true; + } else if (inImagePool) { + QVGImagePool::instance()->useImage(this); } if (!source.isNull() && recreate) { @@ -282,8 +292,13 @@ VGImage QVGPixmapData::toVGImage(qreal opacity) // Create an alternative image for the selected opacity. if (vgImageOpacity == VG_INVALID_HANDLE || cachedOpacity != opacity) { if (vgImageOpacity == VG_INVALID_HANDLE) { - vgImageOpacity = vgCreateImage - (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + if (inImagePool) { + vgImageOpacity = QVGImagePool::instance()->createImageForPixmap + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this); + } else { + vgImageOpacity = vgCreateImage + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + } // Bail out if we run out of GPU memory - try again next time. if (vgImageOpacity == VG_INVALID_HANDLE) @@ -308,6 +323,14 @@ VGImage QVGPixmapData::toVGImage(qreal opacity) #endif } +void QVGPixmapData::detachImageFromPool() +{ + if (inImagePool) { + QVGImagePool::instance()->detachImage(this); + inImagePool = false; + } +} + void QVGPixmapData::hibernate() { // If the image was imported (e.g, from an SgImage under Symbian), @@ -319,6 +342,14 @@ void QVGPixmapData::hibernate() destroyImageAndContext(); } +void QVGPixmapData::reclaimImages() +{ + if (!inImagePool) + return; + forceToImage(); + destroyImages(); +} + extern int qt_defaultDpiX(); extern int qt_defaultDpiY(); @@ -411,14 +442,7 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) if (!context) context = qt_vg_create_context(0, QInternal::Pixmap); - if (vgImage != VG_INVALID_HANDLE) { - vgDestroyImage(vgImage); - vgImage = VG_INVALID_HANDLE; - } - if (vgImageOpacity != VG_INVALID_HANDLE) { - vgDestroyImage(vgImageOpacity); - vgImageOpacity = VG_INVALID_HANDLE; - } + destroyImages(); prevSize = QSize(); TInt err = 0; diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h index c0bb098..4ff95c1 100644 --- a/src/openvg/qpixmapdata_vg_p.h +++ b/src/openvg/qpixmapdata_vg_p.h @@ -63,6 +63,7 @@ class RSGImage; QT_BEGIN_NAMESPACE class QEglContext; +class QVGImagePool; #if !defined(QT_NO_EGL) class QVGPixmapData; @@ -101,6 +102,9 @@ public: // Return the VGImage form for a specific opacity setting. virtual VGImage toVGImage(qreal opacity); + // Detach this image from the image pool. + virtual void detachImageFromPool(); + // Release the VG resources associated with this pixmap and copy // the pixmap's contents out of the GPU back into main memory. // The VG resource will be automatically recreated the next time @@ -109,6 +113,10 @@ public: // process via a SgImage). virtual void hibernate(); + // Called when the QVGImagePool wants to reclaim this pixmap's + // VGImage objects to reuse storage. + virtual void reclaimImages(); + QSize size() const { return QSize(w, h); } #if defined(Q_OS_SYMBIAN) @@ -123,8 +131,13 @@ protected: void cleanup(); #endif -#if !defined(QT_NO_EGL) private: + QVGPixmapData *nextLRU; + QVGPixmapData *prevLRU; + bool inLRU; + friend class QVGImagePool; + +#if !defined(QT_NO_EGL) QVGPixmapData *next; QVGPixmapData *prev; @@ -140,6 +153,7 @@ protected: qreal cachedOpacity; mutable QImage source; mutable bool recreate; + bool inImagePool; #if !defined(QT_NO_EGL) mutable QEglContext *context; #endif @@ -148,6 +162,7 @@ protected: QImage::Format sourceFormat() const; void destroyImageAndContext(); + void destroyImages(); }; QT_END_NAMESPACE diff --git a/src/openvg/qpixmapfilter_vg.cpp b/src/openvg/qpixmapfilter_vg.cpp index e17c728..aa526ed 100644 --- a/src/openvg/qpixmapfilter_vg.cpp +++ b/src/openvg/qpixmapfilter_vg.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qpixmapfilter_vg_p.h" +#include "qvgimagepool_p.h" #include <QtCore/qvarlengtharray.h> #include <QtGui/qpainter.h> @@ -82,9 +83,9 @@ void QVGPixmapConvolutionFilter::draw return; QSize size = pd->size(); - VGImage dstImage = vgCreateImage + VGImage dstImage = QVGImagePool::instance()->createTemporaryImage (VG_sARGB_8888_PRE, size.width(), size.height(), - VG_IMAGE_QUALITY_FASTER); + VG_IMAGE_QUALITY_FASTER, pd); if (dstImage == VG_INVALID_HANDLE) return; @@ -124,7 +125,7 @@ void QVGPixmapConvolutionFilter::draw if(child != dstImage) vgDestroyImage(child); - vgDestroyImage(dstImage); + QVGImagePool::instance()->releaseImage(0, dstImage); } QVGPixmapColorizeFilter::QVGPixmapColorizeFilter() @@ -155,9 +156,9 @@ void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const return; QSize size = pd->size(); - VGImage dstImage = vgCreateImage + VGImage dstImage = QVGImagePool::instance()->createTemporaryImage (VG_sARGB_8888_PRE, size.width(), size.height(), - VG_IMAGE_QUALITY_FASTER); + VG_IMAGE_QUALITY_FASTER, pd); if (dstImage == VG_INVALID_HANDLE) return; @@ -217,7 +218,7 @@ void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const if(child != dstImage) vgDestroyImage(child); - vgDestroyImage(dstImage); + QVGImagePool::instance()->releaseImage(0, dstImage); } QVGPixmapDropShadowFilter::QVGPixmapDropShadowFilter() @@ -248,9 +249,9 @@ void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, con return; QSize size = pd->size(); - VGImage dstImage = vgCreateImage + VGImage dstImage = QVGImagePool::instance()->createTemporaryImage (VG_A_8, size.width(), size.height(), - VG_IMAGE_QUALITY_FASTER); + VG_IMAGE_QUALITY_FASTER, pd); if (dstImage == VG_INVALID_HANDLE) return; @@ -282,7 +283,7 @@ void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, con if(child != dstImage) vgDestroyImage(child); - vgDestroyImage(dstImage); + QVGImagePool::instance()->releaseImage(0, dstImage); // Now draw the actual pixmap over the top. painter->drawPixmap(dest, src, srect); @@ -316,9 +317,9 @@ void QVGPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPi return; QSize size = pd->size(); - VGImage dstImage = vgCreateImage + VGImage dstImage = QVGImagePool::instance()->createTemporaryImage (VG_sARGB_8888_PRE, size.width(), size.height(), - VG_IMAGE_QUALITY_FASTER); + VG_IMAGE_QUALITY_FASTER, pd); if (dstImage == VG_INVALID_HANDLE) return; @@ -347,7 +348,7 @@ void QVGPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPi if(child != dstImage) vgDestroyImage(child); - vgDestroyImage(dstImage); + QVGImagePool::instance()->releaseImage(0, dstImage); } #endif diff --git a/src/openvg/qvgimagepool.cpp b/src/openvg/qvgimagepool.cpp new file mode 100644 index 0000000..93e6e03 --- /dev/null +++ b/src/openvg/qvgimagepool.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvgimagepool_p.h" +#include "qpixmapdata_vg_p.h" + +QT_BEGIN_NAMESPACE + +static QVGImagePool *qt_vg_image_pool = 0; + +class QVGImagePoolPrivate +{ +public: + QVGImagePoolPrivate() : lruFirst(0), lruLast(0) {} + + QVGPixmapData *lruFirst; + QVGPixmapData *lruLast; +}; + +QVGImagePool::QVGImagePool() + : d_ptr(new QVGImagePoolPrivate()) +{ +} + +QVGImagePool::~QVGImagePool() +{ +} + +QVGImagePool *QVGImagePool::instance() +{ + if (!qt_vg_image_pool) + qt_vg_image_pool = new QVGImagePool(); + return qt_vg_image_pool; +} + +void QVGImagePool::setImagePool(QVGImagePool *pool) +{ + if (qt_vg_image_pool != pool) + delete qt_vg_image_pool; + qt_vg_image_pool = pool; +} + +VGImage QVGImagePool::createTemporaryImage(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality, + QVGPixmapData *keepData) +{ + VGImage image; + do { + image = vgCreateImage(format, width, height, allowedQuality); + if (image != VG_INVALID_HANDLE) + return image; + } while (reclaimSpace(format, width, height, keepData)); + qWarning("QVGImagePool: cannot reclaim sufficient space for a %dx%d temporary image", + width, height); + return VG_INVALID_HANDLE; +} + +VGImage QVGImagePool::createImageForPixmap(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality, + QVGPixmapData *data) +{ + VGImage image; + do { + image = vgCreateImage(format, width, height, allowedQuality); + if (image != VG_INVALID_HANDLE) { + if (data) + moveToHeadOfLRU(data); + return image; + } + } while (reclaimSpace(format, width, height, data)); + qWarning("QVGImagePool: cannot reclaim sufficient space for a %dx%d pixmap", + width, height); + return VG_INVALID_HANDLE; +} + +VGImage QVGImagePool::createPermanentImage(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality) +{ + VGImage image; + do { + image = vgCreateImage(format, width, height, allowedQuality); + if (image != VG_INVALID_HANDLE) + return image; + } while (reclaimSpace(format, width, height, 0)); + qWarning("QVGImagePool: cannot reclaim sufficient space for a %dx%d image", + width, height); + return VG_INVALID_HANDLE; +} + +void QVGImagePool::releaseImage(QVGPixmapData *data, VGImage image) +{ + // Very simple strategy at the moment: just destroy the image. + if (data) + removeFromLRU(data); + vgDestroyImage(image); +} + +void QVGImagePool::useImage(QVGPixmapData *data) +{ + moveToHeadOfLRU(data); +} + +void QVGImagePool::detachImage(QVGPixmapData *data) +{ + removeFromLRU(data); +} + +bool QVGImagePool::reclaimSpace(VGImageFormat format, + VGint width, VGint height, + QVGPixmapData *data) +{ + Q_UNUSED(format); // For future use in picking the best image to eject. + Q_UNUSED(width); + Q_UNUSED(height); + + if (data) + moveToHeadOfLRU(data); + + QVGPixmapData *lrudata = pixmapLRU(); + if (lrudata && lrudata != data) { + lrudata->reclaimImages(); + return true; + } + + return false; +} + +void QVGImagePool::hibernate() +{ + // Nothing to do here at the moment since the pool does not + // retain VGImage's after they have been released. +} + +void QVGImagePool::moveToHeadOfLRU(QVGPixmapData *data) +{ + Q_D(QVGImagePool); + if (data->inLRU) { + if (!data->prevLRU) + return; // Already at the head of the list. + removeFromLRU(data); + } + data->inLRU = true; + data->nextLRU = d->lruFirst; + data->prevLRU = 0; + if (d->lruFirst) + d->lruFirst->prevLRU = data; + else + d->lruLast = data; + d->lruFirst = data; +} + +void QVGImagePool::removeFromLRU(QVGPixmapData *data) +{ + Q_D(QVGImagePool); + if (!data->inLRU) + return; + if (data->nextLRU) + data->nextLRU->prevLRU = data->prevLRU; + else + d->lruLast = data->prevLRU; + if (data->prevLRU) + data->prevLRU->nextLRU = data->nextLRU; + else + d->lruFirst = data->nextLRU; + data->inLRU = false; +} + +QVGPixmapData *QVGImagePool::pixmapLRU() +{ + Q_D(QVGImagePool); + return d->lruLast; +} + +QT_END_NAMESPACE diff --git a/src/openvg/qvgimagepool_p.h b/src/openvg/qvgimagepool_p.h new file mode 100644 index 0000000..66a4998 --- /dev/null +++ b/src/openvg/qvgimagepool_p.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVGIMAGEPOOL_P_H +#define QVGIMAGEPOOL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qvg.h" +#include <QtCore/qscopedpointer.h> + +QT_BEGIN_NAMESPACE + +class QVGPixmapData; +class QVGImagePoolPrivate; + +class Q_OPENVG_EXPORT QVGImagePool +{ +public: + QVGImagePool(); + virtual ~QVGImagePool(); + + static QVGImagePool *instance(); + + // This function can be used from system-specific graphics system + // plugins to alter the image allocation strategy. + static void setImagePool(QVGImagePool *pool); + + // Create a new VGImage from the pool with the specified parameters + // that is not associated with a pixmap. The VGImage is returned to + // the pool when releaseImage() is called. + // + // This function will call reclaimSpace() when vgCreateImage() fails. + // + // This function is typically called when allocating temporary + // VGImage's for pixmap filters. The "keepData" object will not + // be reclaimed if reclaimSpace() needs to be called. + virtual VGImage createTemporaryImage(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality, + QVGPixmapData *keepData = 0); + + // Create a new VGImage with the specified parameters and associate + // it with "data". The QVGPixmapData will be notified when the + // VGImage needs to be reclaimed by the pool. + // + // This function will call reclaimSpace() when vgCreateImage() fails. + virtual VGImage createImageForPixmap(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality, + QVGPixmapData *data); + + // Create a permanent VGImage with the specified parameters. + // If there is insufficient space for the vgCreateImage call, + // then this function will call reclaimSpace() and try again. + // + // The caller is responsible for calling vgDestroyImage() + // when it no longer needs the VGImage, as the image is not + // recorded in the image pool. + // + // This function is typically used for pattern brushes where + // the OpenVG engine is responsible for managing the lifetime + // of the VGImage, destroying it automatically when the brush + // is no longer in use. + virtual VGImage createPermanentImage(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality); + + // Release a VGImage that is no longer required. + virtual void releaseImage(QVGPixmapData *data, VGImage image); + + // Notify the pool that a QVGPixmapData object is using + // an image again. This allows the pool to move the image + // within a least-recently-used list of QVGPixmapData objects. + virtual void useImage(QVGPixmapData *data); + + // Notify the pool that the VGImage's associated with a + // QVGPixmapData are being detached from the pool. The caller + // will become responsible for calling vgDestroyImage(). + virtual void detachImage(QVGPixmapData *data); + + // Reclaim space for an image allocation with the specified parameters. + // Returns true if space was reclaimed, or false if there is no + // further space that can be reclaimed. The "data" parameter + // indicates the pixmap that is trying to obtain space which should + // not itself be reclaimed. + virtual bool reclaimSpace(VGImageFormat format, + VGint width, VGint height, + QVGPixmapData *data); + + // Hibernate the image pool because the context is about to be + // destroyed. All VGImage's left in the pool should be released. + virtual void hibernate(); + +protected: + // Helper functions for managing the LRU list of QVGPixmapData objects. + void moveToHeadOfLRU(QVGPixmapData *data); + void removeFromLRU(QVGPixmapData *data); + QVGPixmapData *pixmapLRU(); + +private: + QScopedPointer<QVGImagePoolPrivate> d_ptr; + + Q_DECLARE_PRIVATE(QVGImagePool) + Q_DISABLE_COPY(QVGImagePool) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qwindowsurface_vgegl.cpp b/src/openvg/qwindowsurface_vgegl.cpp index 1571083..bda6096 100644 --- a/src/openvg/qwindowsurface_vgegl.cpp +++ b/src/openvg/qwindowsurface_vgegl.cpp @@ -42,6 +42,7 @@ #include "qwindowsurface_vgegl_p.h" #include "qpaintengine_vg_p.h" #include "qpixmapdata_vg_p.h" +#include "qvgimagepool_p.h" #include "qvg_p.h" #if !defined(QT_NO_EGL) @@ -360,6 +361,9 @@ void qt_vg_hibernate_pixmaps(QVGSharedContext *shared) pd = pd->next; } + // Hibernate any remaining VGImage's in the image pool. + QVGImagePool::instance()->hibernate(); + // Don't need the current context any more. shared->context->lazyDoneCurrent(); diff --git a/src/qt_install.pri b/src/qt_install.pri index ebeac8d..5b29942 100644 --- a/src/qt_install.pri +++ b/src/qt_install.pri @@ -30,6 +30,12 @@ qt_install_headers { targ_headers.files = $$INSTALL_HEADERS targ_headers.path = $$[QT_INSTALL_HEADERS]/$$TARGET INSTALLS += targ_headers + + contains(QT_CONFIG,private_tests) { + private_headers.files = $$SYNCQT.PRIVATE_HEADER_FILES + private_headers.path = $$[QT_INSTALL_HEADERS]/$$TARGET/private + INSTALLS += private_headers + } } embedded:equals(TARGET, QtGui) { diff --git a/src/s60installs/eabi/QtGuiu.def b/src/s60installs/eabi/QtGuiu.def index 429ca79..bfad2e7 100644 --- a/src/s60installs/eabi/QtGuiu.def +++ b/src/s60installs/eabi/QtGuiu.def @@ -11741,4 +11741,45 @@ EXPORTS _ZN11QVectorPathD2Ev @ 11740 NONAME _ZNK11QVectorPath12addCacheDataEP14QPaintEngineExPvPFvS1_S2_E @ 11741 NONAME _ZNK20QGraphicsItemPrivate20discardUpdateRequestEbbb @ 11742 NONAME + _ZN11QEglContext10extensionsEv @ 11743 NONAME + _ZN11QEglContext10getDisplayEP12QPaintDevice @ 11744 NONAME + _ZN11QEglContext10waitClientEv @ 11745 NONAME + _ZN11QEglContext10waitNativeEv @ 11746 NONAME + _ZN11QEglContext11doneCurrentEv @ 11747 NONAME + _ZN11QEglContext11errorStringEi @ 11748 NONAME + _ZN11QEglContext11makeCurrentEi @ 11749 NONAME + _ZN11QEglContext11openDisplayEP12QPaintDevice @ 11750 NONAME + _ZN11QEglContext11swapBuffersEi @ 11751 NONAME + _ZN11QEglContext12chooseConfigERK14QEglPropertiesN4QEgl16PixelFormatMatchE @ 11752 NONAME + _ZN11QEglContext12hasExtensionEPKc @ 11753 NONAME + _ZN11QEglContext13createContextEPS_PK14QEglProperties @ 11754 NONAME + _ZN11QEglContext13createSurfaceEP12QPaintDevicePK14QEglProperties @ 11755 NONAME + _ZN11QEglContext14currentContextEN4QEgl3APIE @ 11756 NONAME + _ZN11QEglContext14defaultDisplayEP12QPaintDevice @ 11757 NONAME + _ZN11QEglContext14destroySurfaceEi @ 11758 NONAME + _ZN11QEglContext14dumpAllConfigsEv @ 11759 NONAME + _ZN11QEglContext15lazyDoneCurrentEv @ 11760 NONAME + _ZN11QEglContext17setCurrentContextEN4QEgl3APIEPS_ @ 11761 NONAME + _ZN11QEglContext7destroyEv @ 11762 NONAME + _ZN11QEglContextC1Ev @ 11763 NONAME + _ZN11QEglContextC2Ev @ 11764 NONAME + _ZN11QEglContextD1Ev @ 11765 NONAME + _ZN11QEglContextD2Ev @ 11766 NONAME + _ZN14QEglProperties11removeValueEi @ 11767 NONAME + _ZN14QEglProperties14dumpAllConfigsEv @ 11768 NONAME + _ZN14QEglProperties14setPixelFormatEN6QImage6FormatE @ 11769 NONAME + _ZN14QEglProperties17setRenderableTypeEN4QEgl3APIE @ 11770 NONAME + _ZN14QEglProperties19reduceConfigurationEv @ 11771 NONAME + _ZN14QEglProperties20setPaintDeviceFormatEP12QPaintDevice @ 11772 NONAME + _ZN14QEglProperties8setValueEii @ 11773 NONAME + _ZN14QEglPropertiesC1Ei @ 11774 NONAME + _ZN14QEglPropertiesC1Ev @ 11775 NONAME + _ZN14QEglPropertiesC2Ei @ 11776 NONAME + _ZN14QEglPropertiesC2Ev @ 11777 NONAME + _ZNK11QEglContext12configAttribEiPi @ 11778 NONAME + _ZNK11QEglContext16configPropertiesEi @ 11779 NONAME + _ZNK11QEglContext7isValidEv @ 11780 NONAME + _ZNK11QEglContext9isCurrentEv @ 11781 NONAME + _ZNK14QEglProperties5valueEi @ 11782 NONAME + _ZNK14QEglProperties8toStringEv @ 11783 NONAME diff --git a/src/s60installs/eabi/QtOpenVGu.def b/src/s60installs/eabi/QtOpenVGu.def index 8458983..7526632 100644 --- a/src/s60installs/eabi/QtOpenVGu.def +++ b/src/s60installs/eabi/QtOpenVGu.def @@ -1,8 +1,8 @@ EXPORTS _Z16qPixmapToVGImageRK7QPixmap @ 1 NONAME - _Z20qt_vg_create_contextP12QPaintDevice @ 2 NONAME + _Z20qt_vg_create_contextP12QPaintDevice @ 2 NONAME ABSENT _Z20qt_vg_shared_surfacev @ 3 NONAME - _Z21qt_vg_destroy_contextP11QEglContext @ 4 NONAME + _Z21qt_vg_destroy_contextP11QEglContext @ 4 NONAME ABSENT _Z24qt_vg_image_to_vg_formatN6QImage6FormatE @ 5 NONAME _Z25qt_vg_config_to_vg_formatP11QEglContext @ 6 NONAME _Z25qt_vg_create_paint_enginev @ 7 NONAME @@ -169,4 +169,8 @@ EXPORTS _ZThn8_NK16QVGWindowSurface6metricEN12QPaintDevice17PaintDeviceMetricE @ 168 NONAME _ZN14QVGPaintEngine10fillRegionERK7QRegionRK6QColorRK5QSize @ 169 NONAME _ZN20QVGCompositionHelper10blitWindowEmRK5QSizeRK5QRectRK6QPointi @ 170 NONAME + _Z20qt_vg_create_contextP12QPaintDevicei @ 171 NONAME + _Z21qt_vg_destroy_contextP11QEglContexti @ 172 NONAME + _ZN13QVGPixmapData22destroyImageAndContextEv @ 173 NONAME + _ZN13QVGPixmapData9hibernateEv @ 174 NONAME diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index b6aa872..1879367 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -33,6 +33,7 @@ #include "qscriptvalue_p.h" #include "qscriptvalueiterator.h" #include "qscriptclass.h" +#include "qscriptcontextinfo.h" #include "qscriptprogram.h" #include "qscriptprogram_p.h" #include "qdebug.h" @@ -698,9 +699,9 @@ JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState *exec, JSC::JSObject*, JS return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): third argument (n) must be a number"); #ifndef QT_NO_QOBJECT QString context; -// ### implement context resolution -// if (ctx->parentContext()) -// context = QFileInfo(ctx->parentContext()->fileName()).baseName(); + QScriptContext *ctx = QScriptEnginePrivate::contextForFrame(exec); + if (ctx && ctx->parentContext()) + context = QFileInfo(QScriptContextInfo(ctx->parentContext()).fileName()).baseName(); #endif QString text(args.at(0).toString(exec)); #ifndef QT_NO_QOBJECT diff --git a/src/sql/drivers/sqlite/qsql_sqlite.cpp b/src/sql/drivers/sqlite/qsql_sqlite.cpp index 8355de2..c62f15c 100644 --- a/src/sql/drivers/sqlite/qsql_sqlite.cpp +++ b/src/sql/drivers/sqlite/qsql_sqlite.cpp @@ -122,14 +122,14 @@ public: sqlite3_stmt *stmt; - uint skippedStatus: 1; // the status of the fetchNext() that's skipped - uint skipRow: 1; // skip the next fetchNext()? - uint utf8: 1; + bool skippedStatus; // the status of the fetchNext() that's skipped + bool skipRow; // skip the next fetchNext()? QSqlRecord rInf; + QVector<QVariant> firstRow; }; QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult* res) : q(res), access(0), - stmt(0), skippedStatus(false), skipRow(false), utf8(false) + stmt(0), skippedStatus(false), skipRow(false) { } @@ -189,10 +189,17 @@ bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int i // already fetched Q_ASSERT(!initialFetch); skipRow = false; + for(int i=0;i<firstRow.count();i++) + values[i]=firstRow[i]; return skippedStatus; } skipRow = initialFetch; + if(initialFetch) { + firstRow.clear(); + firstRow.resize(sqlite3_column_count(stmt)); + } + if (!stmt) { q->setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"), QCoreApplication::translate("QSQLiteResult", "No query"), QSqlError::ConnectionError)); @@ -399,7 +406,7 @@ bool QSQLiteResult::exec() "Parameter count mismatch"), QString(), QSqlError::StatementError)); return false; } - d->skippedStatus = d->fetchNext(cache(), 0, true); + d->skippedStatus = d->fetchNext(d->firstRow, 0, true); if (lastError().isValid()) { setSelect(false); setActive(false); diff --git a/src/sql/kernel/qsqlcachedresult.cpp b/src/sql/kernel/qsqlcachedresult.cpp index b4a9241..2e4d19e 100644 --- a/src/sql/kernel/qsqlcachedresult.cpp +++ b/src/sql/kernel/qsqlcachedresult.cpp @@ -278,6 +278,11 @@ bool QSqlCachedResult::cacheNext() if (d->atEnd) return false; + if(isForwardOnly()) { + d->cache.clear(); + d->cache.resize(d->colCount); + } + if (!gotoNext(d->cache, d->nextIndex())) { d->revertLast(); d->atEnd = true; diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 92d29ae..4215e97 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -256,6 +256,7 @@ SUBDIRS += \ qprinter \ qprinterinfo \ qprocess \ + qprocessenvironment \ qprogressbar \ qprogressdialog \ qpropertyanimation \ @@ -442,7 +443,6 @@ SUBDIRS += \ qsharedmemory \ qsidebar \ qsizegrip \ - qsoftkeymanager \ qsqldriver \ qsystemsemaphore \ qtconcurrentfilter \ @@ -477,6 +477,10 @@ embedded:!wince* { SUBDIRS += qtextpiecetable } +symbian { + SUBDIRS += qsoftkeymanager +} + # Enable the tests specific to QtXmlPatterns. If you add a test, remember to # update runQtXmlPatternsTests.sh too. Remember that this file, auto.pro, is # not respected by some test system, they just have a script which loop over diff --git a/tests/auto/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/qabstractitemview/tst_qabstractitemview.cpp index 6479829..bf3af63 100644 --- a/tests/auto/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/qabstractitemview/tst_qabstractitemview.cpp @@ -48,6 +48,7 @@ #include <qlistview.h> #include <qlistwidget.h> #include <qtableview.h> +#include <qtablewidget.h> #include <qtreeview.h> #include <qtreewidget.h> #include <qheaderview.h> @@ -226,6 +227,7 @@ private slots: void shiftSelectionAfterRubberbandSelection(); void ctrlRubberbandSelection(); void QTBUG6407_extendedSelection(); + void QTBUG6753_selectOnSelection(); }; class MyAbstractItemDelegate : public QAbstractItemDelegate @@ -1475,5 +1477,26 @@ void tst_QAbstractItemView::QTBUG6407_extendedSelection() } +void tst_QAbstractItemView::QTBUG6753_selectOnSelection() +{ + QTableWidget table(5, 5); + for (int i = 0; i < table.rowCount(); ++i) + for (int j = 0; j < table.columnCount(); ++j) + table.setItem(i, j, new QTableWidgetItem("choo-be-doo-wah")); + + table.show(); + table.setSelectionMode(QAbstractItemView::ExtendedSelection); + table.selectAll(); + QTest::qWaitForWindowShown(&table); + QModelIndex item = table.model()->index(1,1); + QRect itemRect = table.visualRect(item); + QTest::mouseMove(table.viewport(), itemRect.center()); + QTest::mouseClick(table.viewport(), Qt::LeftButton, Qt::NoModifier, itemRect.center()); + QTest::qWait(20); + + QCOMPARE(table.selectedItems().count(), 1); + QCOMPARE(table.selectedItems().first(), table.item(item.row(), item.column())); +} + QTEST_MAIN(tst_QAbstractItemView) #include "tst_qabstractitemview.moc" diff --git a/tests/auto/qfile/tst_qfile.cpp b/tests/auto/qfile/tst_qfile.cpp index 7ee5665..2b2f431 100644 --- a/tests/auto/qfile/tst_qfile.cpp +++ b/tests/auto/qfile/tst_qfile.cpp @@ -220,6 +220,9 @@ public: private: enum FileType { OpenQFile, OpenFd, OpenStream }; + void openStandardStreamsFileDescriptors(); + void openStandardStreamsBufferedStreams(); + bool openFd(QFile &file, QIODevice::OpenMode mode) { int fdMode = QT_OPEN_LARGEFILE | QT_OPEN_BINARY; @@ -554,6 +557,10 @@ void tst_QFile::size() QFETCH( QString, filename ); QFETCH( qint64, size ); +#ifdef Q_WS_WINCE + filename = QFileInfo(filename).absoluteFilePath(); +#endif + { QFile f( filename ); QCOMPARE( f.size(), size ); @@ -564,24 +571,29 @@ void tst_QFile::size() { QFile f; - int fd = QT_OPEN(filename.toLocal8Bit().constData(), QT_OPEN_RDONLY); - QVERIFY( fd != -1 ); - QVERIFY( f.open(fd, QIODevice::ReadOnly) ); + FILE* stream = QT_FOPEN(filename.toLocal8Bit().constData(), "rb"); + QVERIFY( stream ); + QVERIFY( f.open(stream, QIODevice::ReadOnly) ); QCOMPARE( f.size(), size ); f.close(); - QT_CLOSE(fd); + fclose(stream); } { +#ifdef Q_WS_WINCE + QSKIP("Currently low level file I/O not well supported on Windows CE", SkipSingle); +#endif QFile f; - FILE* stream = QT_FOPEN(filename.toLocal8Bit().constData(), "rb"); - QVERIFY( stream ); - QVERIFY( f.open(stream, QIODevice::ReadOnly) ); + + int fd = QT_OPEN(filename.toLocal8Bit().constData(), QT_OPEN_RDONLY); + + QVERIFY( fd != -1 ); + QVERIFY( f.open(fd, QIODevice::ReadOnly) ); QCOMPARE( f.size(), size ); f.close(); - fclose(stream); + QT_CLOSE(fd); } } @@ -603,6 +615,7 @@ void tst_QFile::seek() QVERIFY(file.seek(10)); QCOMPARE(file.pos(), qint64(10)); QCOMPARE(file.size(), qint64(0)); + file.close(); QFile::remove("newfile.txt"); } @@ -1128,9 +1141,15 @@ void tst_QFile::copyFallback() QVERIFY(QFile::exists("file-copy-destination.txt")); QVERIFY(!file.isOpen()); +#ifdef Q_WS_WINCE // Need to reset permissions on Windows to be able to delete QVERIFY(QFile::setPermissions("file-copy-destination.txt", - QFile::ReadOwner | QFile::WriteOwner)); + QFile::WriteOther)); +#else + // Need to reset permissions on Windows to be able to delete + QVERIFY(QFile::setPermissions("file-copy-destination.txt", + QFile::ReadOwner | QFile::WriteOwner)); +#endif QVERIFY(QFile::remove("file-copy-destination.txt")); // Fallback copy of open file. @@ -1139,6 +1158,7 @@ void tst_QFile::copyFallback() QVERIFY(QFile::exists("file-copy-destination.txt")); QVERIFY(!file.isOpen()); + file.close(); QFile::remove("file-copy-destination.txt"); } @@ -2239,6 +2259,7 @@ void tst_QFile::rename() QFile file(source); QCOMPARE(file.rename(destination), result); + if (result) QCOMPARE(file.error(), QFile::NoError); else @@ -2367,6 +2388,7 @@ void tst_QFile::appendAndRead() QCOMPARE(readFile.read(1 << j).size(), 1 << j); } + readFile.close(); QFile::remove(QLatin1String("appendfile.txt")); } @@ -2608,10 +2630,15 @@ void tst_QFile::map() QFETCH(QFile::FileError, error); QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile"; + +#ifdef Q_WS_WINCE + fileName = QFileInfo(fileName).absoluteFilePath(); +#endif + if (QFile::exists(fileName)) { QVERIFY(QFile::setPermissions(fileName, QFile::WriteOwner | QFile::ReadOwner | QFile::WriteUser | QFile::ReadUser)); - QFile::remove(fileName); + QFile::remove(fileName); } QFile file(fileName); @@ -2650,8 +2677,13 @@ void tst_QFile::map() QCOMPARE(file.error(), QFile::NoError); // hpux wont let you map multiple times. -#if !defined(Q_OS_HPUX) && !defined(Q_USE_DEPRECATED_MAP_API) +#if !defined(Q_OS_HPUX) && !defined(Q_USE_DEPRECATED_MAP_API) && !defined(Q_OS_WINCE) // exotic test to make sure that multiple maps work + + // note: windows ce does not reference count mutliple maps + // it's essentially just the same reference but it + // cause a resource lock on the file which prevents it + // from being removed uchar *memory1 = file.map(0, file.size()); uchar *memory1 = file.map(0, file.size()); QCOMPARE(file.error(), QFile::NoError); uchar *memory2 = file.map(0, file.size()); @@ -2687,7 +2719,6 @@ void tst_QFile::map() QVERIFY(!memory); QVERIFY(file.setPermissions(originalPermissions)); } - QVERIFY(file.remove()); } @@ -2800,8 +2831,14 @@ void tst_QFile::openDirectory() f1.close(); } -void tst_QFile::openStandardStreams() +void tst_QFile::openStandardStreamsFileDescriptors() { +#ifdef Q_WS_WINCE + //allthough Windows CE (not mobile!) has functions that allow redirecting + //the standard file descriptors to a file (see SetStdioPathW/GetStdioPathW) + //it does not have functions to simply open them like below . + QSKIP("Opening standard streams on Windows CE via descriptor not implemented", SkipAll); +#endif // Using file descriptors { QFile in; @@ -2826,7 +2863,13 @@ void tst_QFile::openStandardStreams() QCOMPARE( err.size(), (qint64)0 ); QVERIFY( err.isSequential() ); } +} +void tst_QFile::openStandardStreamsBufferedStreams() +{ +#if defined (Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QSKIP("Unix only test.", SkipAll); +#endif // Using streams { QFile in; @@ -2853,6 +2896,12 @@ void tst_QFile::openStandardStreams() } } +void tst_QFile::openStandardStreams() +{ + openStandardStreamsFileDescriptors(); + openStandardStreamsBufferedStreams(); +} + void tst_QFile::writeNothing() { for (int i = 0; i < 3; ++i) { diff --git a/tests/auto/qfileinfo/tst_qfileinfo.cpp b/tests/auto/qfileinfo/tst_qfileinfo.cpp index cd58fd6..1445f5b 100644 --- a/tests/auto/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/qfileinfo/tst_qfileinfo.cpp @@ -513,9 +513,11 @@ void tst_QFileInfo::canonicalFilePath() QFileInfo info("/tmp/../../../../../../../../../../../../../../../../../"); info.canonicalFilePath(); +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) // This used to crash on Mac QFileInfo dontCrash(QLatin1String("/")); QCOMPARE(dontCrash.canonicalFilePath(), QLatin1String("/")); +#endif #ifndef Q_OS_WIN // test symlinks diff --git a/tests/auto/qgraphicseffect/tst_qgraphicseffect.cpp b/tests/auto/qgraphicseffect/tst_qgraphicseffect.cpp index 259df4d..69fc118 100644 --- a/tests/auto/qgraphicseffect/tst_qgraphicseffect.cpp +++ b/tests/auto/qgraphicseffect/tst_qgraphicseffect.cpp @@ -69,6 +69,7 @@ private slots: void opacity(); void grayscale(); void colorize(); + void drawPixmapItem(); }; void tst_QGraphicsEffect::initTestCase() @@ -465,6 +466,54 @@ void tst_QGraphicsEffect::colorize() QCOMPARE(image.pixel(10, 10), qRgb(122, 193, 66)); } +class PixmapItemEffect : public QGraphicsEffect +{ +public: + PixmapItemEffect(const QPixmap &source) + : QGraphicsEffect() + , pixmap(source) + , repaints(0) + {} + + QRectF boundingRectFor(const QRectF &rect) const + { return rect; } + + void draw(QPainter *painter) + { + QVERIFY(sourcePixmap(Qt::LogicalCoordinates).pixmapData() == pixmap.pixmapData()); + QVERIFY((painter->worldTransform().type() <= QTransform::TxTranslate) == (sourcePixmap(Qt::DeviceCoordinates).pixmapData() == pixmap.pixmapData())); + + ++repaints; + } + QPixmap pixmap; + int repaints; +}; + +void tst_QGraphicsEffect::drawPixmapItem() +{ + QImage image(32, 32, QImage::Format_RGB32); + QPainter p(&image); + p.fillRect(0, 0, 32, 16, Qt::blue); + p.fillRect(0, 16, 32, 16, Qt::red); + p.end(); + + QGraphicsScene scene; + QGraphicsPixmapItem *item = new QGraphicsPixmapItem(QPixmap::fromImage(image)); + scene.addItem(item); + + PixmapItemEffect *effect = new PixmapItemEffect(item->pixmap()); + item->setGraphicsEffect(effect); + + QGraphicsView view(&scene); + view.show(); + QTest::qWaitForWindowShown(&view); + + item->rotate(180); + QTest::qWait(50); + + QTRY_VERIFY(effect->repaints >= 2); +} + QTEST_MAIN(tst_QGraphicsEffect) #include "tst_qgraphicseffect.moc" diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index a4931ab..03a587a 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -1354,6 +1354,7 @@ void tst_QGraphicsItem::selected() view.setFixedSize(250, 250); view.show(); + QTest::qWaitForWindowShown(&view); qApp->processEvents(); qApp->processEvents(); diff --git a/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp b/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp index d3087dc..ab110e6 100644 --- a/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp +++ b/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp @@ -146,7 +146,7 @@ void tst_QGraphicsLinearLayout::initTestCase() { // since the style will influence the results, we have to ensure // that the tests are run using the same style on all platforms -#ifdef Q_WS_S60 +#if defined( Q_WS_S60 )|| defined (Q_WS_WINCE) QApplication::setStyle(new QWindowsStyle); #else QApplication::setStyle(new QPlastiqueStyle); diff --git a/tests/auto/qobject/tst_qobject.cpp b/tests/auto/qobject/tst_qobject.cpp index a2524aa..75d7a0a 100644 --- a/tests/auto/qobject/tst_qobject.cpp +++ b/tests/auto/qobject/tst_qobject.cpp @@ -126,6 +126,7 @@ private slots: void deleteQObjectWhenDeletingEvent(); void overloads(); void isSignalConnected(); + void qMetaObjectConnect(); protected: }; @@ -3125,5 +3126,148 @@ void tst_QObject::isSignalConnected() QCOMPARE(o.rec, 2); } +void tst_QObject::qMetaObjectConnect() +{ + SenderObject *s = new SenderObject; + ReceiverObject *r1 = new ReceiverObject; + ReceiverObject *r2 = new ReceiverObject; + r1->reset(); + r2->reset(); + ReceiverObject::sequence = 0; + + int signal1Index = s->metaObject()->indexOfSignal("signal1()"); + int signal3Index = s->metaObject()->indexOfSignal("signal3()"); + int slot1Index = r1->metaObject()->indexOfSlot("slot1()"); + int slot2Index = r1->metaObject()->indexOfSlot("slot2()"); + int slot3Index = r1->metaObject()->indexOfSlot("slot3()"); + + QVERIFY(slot1Index > 0); + QVERIFY(slot2Index > 0); + QVERIFY(slot3Index > 0); + + QVERIFY( QMetaObject::connect( s, signal1Index, r1, slot1Index) ); + QVERIFY( QMetaObject::connect( s, signal3Index, r2, slot3Index) ); + QVERIFY( QMetaObject::connect( s, -1, r2, slot2Index) ); + + QCOMPARE( r1->count_slot1, 0 ); + QCOMPARE( r1->count_slot2, 0 ); + QCOMPARE( r1->count_slot3, 0 ); + QCOMPARE( r2->count_slot1, 0 ); + QCOMPARE( r2->count_slot2, 0 ); + QCOMPARE( r2->count_slot3, 0 ); + + s->emitSignal1(); + + QCOMPARE( r1->count_slot1, 1 ); + QCOMPARE( r1->count_slot2, 0 ); + QCOMPARE( r1->count_slot3, 0 ); + QCOMPARE( r2->count_slot1, 0 ); + QCOMPARE( r2->count_slot2, 1 ); + QCOMPARE( r2->count_slot3, 0 ); + + s->emitSignal2(); + s->emitSignal3(); + s->emitSignal4(); + + QCOMPARE( r1->count_slot1, 1 ); + QCOMPARE( r1->count_slot2, 0 ); + QCOMPARE( r1->count_slot3, 0 ); + QCOMPARE( r2->count_slot1, 0 ); + QCOMPARE( r2->count_slot2, 4 ); + QCOMPARE( r2->count_slot3, 1 ); + + QVERIFY( QMetaObject::disconnect( s, signal1Index, r1, slot1Index) ); + QVERIFY( QMetaObject::disconnect( s, signal3Index, r2, slot3Index) ); + QVERIFY( QMetaObject::disconnect( s, -1, r2, slot2Index) ); + + s->emitSignal1(); + s->emitSignal2(); + s->emitSignal3(); + s->emitSignal4(); + + QCOMPARE( r1->count_slot1, 1 ); + QCOMPARE( r1->count_slot2, 0 ); + QCOMPARE( r1->count_slot3, 0 ); + QCOMPARE( r2->count_slot1, 0 ); + QCOMPARE( r2->count_slot2, 4 ); + QCOMPARE( r2->count_slot3, 1 ); + + //some "dynamic" signal + QVERIFY( QMetaObject::connect( s, s->metaObject()->methodOffset() + 20, r1, slot3Index) ); + QVERIFY( QMetaObject::connect( s, s->metaObject()->methodOffset() + 35, r2, slot1Index) ); + QVERIFY( QMetaObject::connect( s, -1, r1, slot2Index) ); + + r1->reset(); + r2->reset(); + + void *args[] = { 0 , 0 }; + QMetaObject::activate(s, s->metaObject()->methodOffset() + 20, args); + QMetaObject::activate(s, s->metaObject()->methodOffset() + 48, args); + QCOMPARE( r1->count_slot1, 0 ); + QCOMPARE( r1->count_slot2, 2 ); + QCOMPARE( r1->count_slot3, 1 ); + QCOMPARE( r2->count_slot1, 0 ); + QCOMPARE( r2->count_slot2, 0 ); + QCOMPARE( r2->count_slot3, 0 ); + + QMetaObject::activate(s, s->metaObject()->methodOffset() + 35, args); + s->emitSignal1(); + s->emitSignal2(); + + QCOMPARE( r1->count_slot1, 0 ); + QCOMPARE( r1->count_slot2, 5 ); + QCOMPARE( r1->count_slot3, 1 ); + QCOMPARE( r2->count_slot1, 1 ); + QCOMPARE( r2->count_slot2, 0 ); + QCOMPARE( r2->count_slot3, 0 ); + + delete s; + r1->reset(); + r2->reset(); + +#define SIGNAL_INDEX(S) obj1.metaObject()->indexOfSignal(QMetaObject::normalizedSignature(#S)) + OverloadObject obj1; + QObject obj2, obj3; + + QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(int)) , r1, slot1Index); + QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *)) , r2, slot1Index); + + QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *, QObject *)) , r1, slot2Index); + QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *)) , r2, slot2Index); + QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(int, int)) , r1, slot3Index); + + emit obj1.sig(0.5); //connected to nothing + emit obj1.sig(1, 'a'); //connected to nothing + QCOMPARE( r1->count_slot1, 0 ); + QCOMPARE( r1->count_slot2, 0 ); + QCOMPARE( r1->count_slot3, 0 ); + QCOMPARE( r2->count_slot1, 0 ); + QCOMPARE( r2->count_slot2, 0 ); + QCOMPARE( r2->count_slot3, 0 ); + + emit obj1.sig(1); //this signal is connected + emit obj1.sig(&obj2); + + QCOMPARE( r1->count_slot1, 1 ); + QCOMPARE( r1->count_slot2, 0 ); + QCOMPARE( r1->count_slot3, 1 ); + QCOMPARE( r2->count_slot1, 0 ); + QCOMPARE( r2->count_slot2, 1 ); + QCOMPARE( r2->count_slot3, 0 ); + + emit obj1.sig(&obj2, &obj3); //this signal is connected + + QCOMPARE( r1->count_slot1, 1 ); + QCOMPARE( r1->count_slot2, 1 ); + QCOMPARE( r1->count_slot3, 1 ); + QCOMPARE( r2->count_slot1, 1 ); + QCOMPARE( r2->count_slot2, 1 ); + QCOMPARE( r2->count_slot3, 0 ); + + delete r1; + delete r2; + +} + QTEST_MAIN(tst_QObject) #include "tst_qobject.moc" diff --git a/tests/auto/qprocessenvironment/qprocessenvironment.pro b/tests/auto/qprocessenvironment/qprocessenvironment.pro new file mode 100644 index 0000000..398facc --- /dev/null +++ b/tests/auto/qprocessenvironment/qprocessenvironment.pro @@ -0,0 +1,5 @@ +load(qttest_p4) + +QT = core + +SOURCES += tst_qprocessenvironment.cpp diff --git a/tests/auto/qprocessenvironment/tst_qprocessenvironment.cpp b/tests/auto/qprocessenvironment/tst_qprocessenvironment.cpp new file mode 100644 index 0000000..1cde33c --- /dev/null +++ b/tests/auto/qprocessenvironment/tst_qprocessenvironment.cpp @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest> +#include <QObject> +#include <QProcessEnvironment> + +// Note: +// in cross-platform tests, ALWAYS use UPPERCASE variable names +// That's because on Windows, the variables are uppercased + +class tst_QProcessEnvironment: public QObject +{ + Q_OBJECT +private slots: + void operator_eq(); + void clearAndIsEmpty(); + void insert(); + void emptyNull(); + void toStringList(); + + void caseSensitivity(); + void systemEnvironment(); + void putenv(); +}; + +void tst_QProcessEnvironment::operator_eq() +{ + QProcessEnvironment e1; + QVERIFY(e1 == e1); + e1.clear(); + QVERIFY(e1 == e1); + + e1 = QProcessEnvironment(); + QProcessEnvironment e2; + QVERIFY(e1 == e2); + + e1.clear(); + QVERIFY(e1 != e2); + + e2.clear(); + + QVERIFY(e1 == e2); +} + +void tst_QProcessEnvironment::clearAndIsEmpty() +{ + QProcessEnvironment e; + e.insert("FOO", "bar"); + QVERIFY(!e.isEmpty()); + e.clear(); + QVERIFY(e.isEmpty()); +} + +void tst_QProcessEnvironment::insert() +{ + QProcessEnvironment e; + e.insert("FOO", "bar"); + QVERIFY(!e.isEmpty()); + QVERIFY(e.contains("FOO")); + QCOMPARE(e.value("FOO"), QString("bar")); + + e.remove("FOO"); + QVERIFY(!e.contains("FOO")); + QVERIFY(e.value("FOO").isNull()); + + e.clear(); + QVERIFY(!e.contains("FOO")); +} + +void tst_QProcessEnvironment::emptyNull() +{ + QProcessEnvironment e; + + e.insert("FOO", ""); + QVERIFY(e.contains("FOO")); + QVERIFY(e.value("FOO").isEmpty()); + QVERIFY(!e.value("FOO").isNull()); + + e.insert("FOO", QString()); + QVERIFY(e.contains("FOO")); + QVERIFY(e.value("FOO").isEmpty()); + // don't test if it's NULL, since we shall not make a guarantee + + e.remove("FOO"); + QVERIFY(!e.contains("FOO")); +} + +void tst_QProcessEnvironment::toStringList() +{ + QProcessEnvironment e; + QVERIFY(e.isEmpty()); + QVERIFY(e.toStringList().isEmpty()); + + e.insert("FOO", "bar"); + QStringList result = e.toStringList(); + QVERIFY(!result.isEmpty()); + QCOMPARE(result.length(), 1); + QCOMPARE(result.at(0), QString("FOO=bar")); + + e.clear(); + e.insert("BAZ", ""); + result = e.toStringList(); + QCOMPARE(result.at(0), QString("BAZ=")); + + e.insert("FOO", "bar"); + e.insert("A", "bc"); + e.insert("HELLO", "World"); + result = e.toStringList(); + QCOMPARE(result.length(), 4); + + // order is not specified, so use contains() + QVERIFY(result.contains("FOO=bar")); + QVERIFY(result.contains("BAZ=")); + QVERIFY(result.contains("A=bc")); + QVERIFY(result.contains("HELLO=World")); +} + +void tst_QProcessEnvironment::caseSensitivity() +{ + QProcessEnvironment e; + e.insert("foo", "bar"); + +#ifdef Q_OS_WIN + // on Windows, it's uppercased + QVERIFY(e.contains("foo")); + QVERIFY(e.contains("FOO")); + QVERIFY(e.contains("FoO")); + + QCOMPARE(e.value("foo"), QString("bar")); + QCOMPARE(e.value("FOO"), QString("bar")); + QCOMPARE(e.value("FoO"), QString("bar")); + + QStringList list = e.toStringList(); + QCOMPARE(list.at(0), QString("FOO=bar")); +#else + // otherwise, it's case sensitive + QVERIFY(e.contains("foo")); + QVERIFY(!e.contains("FOO")); + + e.insert("FOO", "baz"); + QVERIFY(e.contains("FOO")); + QCOMPARE(e.value("FOO"), QString("baz")); + QCOMPARE(e.value("foo"), QString("bar")); + + QStringList list = e.toStringList(); + QVERIFY(list.contains("foo=bar")); + QVERIFY(list.contains("FOO=baz")); +#endif +} + +void tst_QProcessEnvironment::systemEnvironment() +{ + static const char envname[] = "THIS_ENVIRONMENT_VARIABLE_HOPEFULLY_DOESNT_EXIST"; + QByteArray path = qgetenv("PATH"); + QByteArray nonexistant = qgetenv(envname); + QProcessEnvironment system = QProcessEnvironment::systemEnvironment(); + + QVERIFY(nonexistant.isNull()); + +#ifdef Q_WS_WINCE + // Windows CE has no environment + QVERIFY(path.isEmpty()); + QVERIFY(!system.contains("PATH")); + QVERIFY(system.isEmpty()); +#else + // all other system have environments + if (path.isEmpty()) + QFAIL("Could not find the PATH environment variable -- please correct the test environment"); + + QVERIFY(system.contains("PATH")); + QCOMPARE(system.value("PATH"), QString::fromLocal8Bit(path)); + + QVERIFY(!system.contains(envname)); + +# ifdef Q_OS_WIN + // check case-insensitive too + QVERIFY(system.contains("path")); + QCOMPARE(system.value("path"), QString::fromLocal8Bit(path)); + + QVERIFY(!system.contains(QString(envname).toLower())); +# endif +#endif +} + +void tst_QProcessEnvironment::putenv() +{ +#ifdef Q_WS_WINCE + QSKIP("Windows CE has no environment", SkipAll); +#else + static const char envname[] = "WE_RE_SETTING_THIS_ENVIRONMENT_VARIABLE"; + static bool testRan = false; + + if (testRan) + QFAIL("You cannot run this test more than once, since we modify the environment"); + testRan = true; + + QByteArray valBefore = qgetenv(envname); + if (!valBefore.isNull()) + QFAIL("The environment variable we set in the environment is already set! -- please correct the test environment"); + QProcessEnvironment eBefore = QProcessEnvironment::systemEnvironment(); + + qputenv(envname, "Hello, World"); + QByteArray valAfter = qgetenv(envname); + if (valAfter != "Hello, World") + QSKIP("Could not test: qputenv did not do its job", SkipAll); + + QProcessEnvironment eAfter = QProcessEnvironment::systemEnvironment(); + + QVERIFY(!eBefore.contains(envname)); + QVERIFY(eAfter.contains(envname)); + QCOMPARE(eAfter.value(envname), QString("Hello, World")); + +# ifdef Q_OS_WIN + // check case-insensitive too + QString lower = envname; + lower = lower.toLower(); + QVERIFY(!eBefore.contains(lower)); + QVERIFY(eAfter.contains(lower)); + QCOMPARE(eAfter.value(lower), QString("Hello, World")); +# endif +#endif +} + +QTEST_MAIN(tst_QProcessEnvironment) + +#include "tst_qprocessenvironment.moc" diff --git a/tests/auto/qsharedmemory/tst_qsharedmemory.cpp b/tests/auto/qsharedmemory/tst_qsharedmemory.cpp index f72b6f7..4148594 100644 --- a/tests/auto/qsharedmemory/tst_qsharedmemory.cpp +++ b/tests/auto/qsharedmemory/tst_qsharedmemory.cpp @@ -756,12 +756,12 @@ void tst_QSharedMemory::simpleProcessProducerConsumer() ++failedProcesses; } - producer.waitForFinished(5000); + QVERIFY(producer.waitForFinished(5000)); bool consumerFailed = false; while (!consumers.isEmpty()) { - consumers.first()->waitForFinished(2000); + QVERIFY(consumers.first()->waitForFinished(3000)); if (consumers.first()->state() == QProcess::Running || consumers.first()->exitStatus() != QProcess::NormalExit || consumers.first()->exitCode() != 0) { diff --git a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp index ed9206c..0cb08f9 100644 --- a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp @@ -73,6 +73,7 @@ private slots: void forwardDeclaration2(); void memoryManagement(); void downCast(); + void functionCallDownCast(); void upCast(); void qobjectWeakManagement(); void noSharedPointerFromWeakQObject(); @@ -503,6 +504,15 @@ void tst_QSharedPointer::downCast() QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1); } +void functionDataByValue(QSharedPointer<Data> p) { Q_UNUSED(p); }; +void functionDataByRef(const QSharedPointer<Data> &p) { Q_UNUSED(p); }; +void tst_QSharedPointer::functionCallDownCast() +{ + QSharedPointer<DerivedData> p(new DerivedData()); + functionDataByValue(p); + functionDataByRef(p); +} + void tst_QSharedPointer::upCast() { QSharedPointer<Data> baseptr = QSharedPointer<Data>(new DerivedData); diff --git a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp index f840ca6..cb4e103 100644 --- a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp +++ b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp @@ -2493,7 +2493,6 @@ void tst_QSqlDatabase::oci_tables() QString systemTableName("system."+qTableName("mypassword")); QVERIFY_SQL(q, exec("CREATE TABLE "+systemTableName+"(name VARCHAR(20))")); QVERIFY(!db.tables().contains(systemTableName.toUpper())); - qDebug() << db.tables(QSql::SystemTables); QVERIFY(db.tables(QSql::SystemTables).contains(systemTableName.toUpper())); } diff --git a/tests/auto/qtouchevent/tst_qtouchevent.cpp b/tests/auto/qtouchevent/tst_qtouchevent.cpp index f95a5c6..da8721c 100644 --- a/tests/auto/qtouchevent/tst_qtouchevent.cpp +++ b/tests/auto/qtouchevent/tst_qtouchevent.cpp @@ -48,6 +48,7 @@ public: QList<QTouchEvent::TouchPoint> touchBeginPoints, touchUpdatePoints, touchEndPoints; bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; + bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd; tst_QTouchEventWidget() : QWidget() @@ -62,6 +63,7 @@ public: touchEndPoints.clear(); seenTouchBegin = seenTouchUpdate = seenTouchEnd = false; acceptTouchBegin = acceptTouchUpdate = acceptTouchEnd = true; + deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; } bool event(QEvent *event) @@ -74,6 +76,8 @@ public: seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd; touchBeginPoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchBegin); + if (deleteInTouchBegin) + delete this; break; case QEvent::TouchUpdate: if (!seenTouchBegin) qWarning("TouchUpdate: have not seen TouchBegin"); @@ -81,6 +85,8 @@ public: seenTouchUpdate = seenTouchBegin && !seenTouchEnd; touchUpdatePoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchUpdate); + if (deleteInTouchUpdate) + delete this; break; case QEvent::TouchEnd: if (!seenTouchBegin) qWarning("TouchEnd: have not seen TouchBegin"); @@ -88,6 +94,8 @@ public: seenTouchEnd = seenTouchBegin && !seenTouchEnd; touchEndPoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchEnd); + if (deleteInTouchEnd) + delete this; break; default: return QWidget::event(event); @@ -102,13 +110,21 @@ public: QList<QTouchEvent::TouchPoint> touchBeginPoints, touchUpdatePoints, touchEndPoints; bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; + bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd; + tst_QTouchEventGraphicsItem **weakpointer; tst_QTouchEventGraphicsItem() - : QGraphicsItem() + : QGraphicsItem(), weakpointer(0) { reset(); } + ~tst_QTouchEventGraphicsItem() + { + if (weakpointer) + *weakpointer = 0; + } + void reset() { touchBeginPoints.clear(); @@ -116,6 +132,7 @@ public: touchEndPoints.clear(); seenTouchBegin = seenTouchUpdate = seenTouchEnd = false; acceptTouchBegin = acceptTouchUpdate = acceptTouchEnd = true; + deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; } QRectF boundingRect() const { return QRectF(0, 0, 10, 10); } @@ -131,6 +148,8 @@ public: seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd; touchBeginPoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchBegin); + if (deleteInTouchBegin) + delete this; break; case QEvent::TouchUpdate: if (!seenTouchBegin) qWarning("TouchUpdate: have not seen TouchBegin"); @@ -138,6 +157,8 @@ public: seenTouchUpdate = seenTouchBegin && !seenTouchEnd; touchUpdatePoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchUpdate); + if (deleteInTouchUpdate) + delete this; break; case QEvent::TouchEnd: if (!seenTouchBegin) qWarning("TouchEnd: have not seen TouchBegin"); @@ -145,6 +166,8 @@ public: seenTouchEnd = seenTouchBegin && !seenTouchEnd; touchEndPoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchEnd); + if (deleteInTouchEnd) + delete this; break; default: return QGraphicsItem::sceneEvent(event); @@ -168,6 +191,8 @@ private slots: void basicRawEventTranslation(); void multiPointRawEventTranslationOnTouchScreen(); void multiPointRawEventTranslationOnTouchPad(); + void deleteInEventHandler(); + void deleteInRawEventTranslation(); }; void tst_QTouchEvent::touchDisabledByDefault() @@ -496,7 +521,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); QVERIFY(res); // the scene accepts the event, since it found an item to send the event to - QVERIFY(touchUpdateEvent.isAccepted()); + QVERIFY(!touchUpdateEvent.isAccepted()); QVERIFY(child.seenTouchUpdate); QVERIFY(!root.seenTouchUpdate); @@ -510,7 +535,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() res = QApplication::sendEvent(view.viewport(), &touchEndEvent); QVERIFY(res); // the scene accepts the event, since it found an item to send the event to - QVERIFY(touchEndEvent.isAccepted()); + QVERIFY(!touchEndEvent.isAccepted()); QVERIFY(child.seenTouchEnd); QVERIFY(!root.seenTouchEnd); } @@ -1059,6 +1084,225 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() } } +void tst_QTouchEvent::deleteInEventHandler() +{ + // QWidget + { + QWidget window; + tst_QTouchEventWidget *child1, *child2, *child3; + child1 = new tst_QTouchEventWidget; + child2 = new tst_QTouchEventWidget; + child3 = new tst_QTouchEventWidget; + child1->setParent(&window); + child2->setParent(&window); + child3->setParent(&window); + child1->setAttribute(Qt::WA_AcceptTouchEvents); + child2->setAttribute(Qt::WA_AcceptTouchEvents); + child3->setAttribute(Qt::WA_AcceptTouchEvents); + child1->deleteInTouchBegin = true; + child2->deleteInTouchUpdate = true; + child3->deleteInTouchEnd = true; + + QList<QTouchEvent::TouchPoint> touchPoints; + touchPoints.append(QTouchEvent::TouchPoint(0)); + QTouchEvent touchBeginEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + touchPoints); + QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointStationary, + touchPoints); + QTouchEvent touchEndEvent(QEvent::TouchEnd, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointReleased, + touchPoints); + QWeakPointer<QWidget> p; + bool res; + + touchBeginEvent.ignore(); + p = child1; + res = QApplication::sendEvent(child1, &touchBeginEvent); + // event is handled, but widget should be deleted + QVERIFY(res && touchBeginEvent.isAccepted() && p.isNull()); + + touchBeginEvent.ignore(); + p = child2; + res = QApplication::sendEvent(child2, &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && !p.isNull()); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(child2, &touchUpdateEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && p.isNull()); + + touchBeginEvent.ignore(); + p = child3; + res = QApplication::sendEvent(child3, &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && !p.isNull()); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(child3, &touchUpdateEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && !p.isNull()); + touchEndEvent.ignore(); + res = QApplication::sendEvent(child3, &touchEndEvent); + QVERIFY(res && touchEndEvent.isAccepted() && p.isNull()); + } + + // QGraphicsView + { + QGraphicsScene scene; + QGraphicsView view(&scene); + tst_QTouchEventGraphicsItem *root, *child1, *child2, *child3; + root = new tst_QTouchEventGraphicsItem; + child1 = new tst_QTouchEventGraphicsItem; + child2 = new tst_QTouchEventGraphicsItem; + child3 = new tst_QTouchEventGraphicsItem; + child1->setParentItem(root); + child2->setParentItem(root); + child3->setParentItem(root); + child1->setZValue(1.); + child2->setZValue(0.); + child3->setZValue(-1.); + child1->setAcceptTouchEvents(true); + child2->setAcceptTouchEvents(true); + child3->setAcceptTouchEvents(true); + child1->deleteInTouchBegin = true; + child2->deleteInTouchUpdate = true; + child3->deleteInTouchEnd = true; + + scene.addItem(root); + view.resize(200, 200); + view.fitInView(scene.sceneRect()); + + QTouchEvent::TouchPoint touchPoint(0); + touchPoint.setState(Qt::TouchPointPressed); + touchPoint.setPos(view.mapFromScene(child1->mapToScene(child1->boundingRect().center()))); + touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint())); + touchPoint.setScenePos(view.mapToScene(touchPoint.pos().toPoint())); + QList<QTouchEvent::TouchPoint> touchPoints; + touchPoints.append(touchPoint); + QTouchEvent touchBeginEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + touchPoints); + touchPoints[0].setState(Qt::TouchPointMoved); + QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointMoved, + touchPoints); + touchPoints[0].setState(Qt::TouchPointReleased); + QTouchEvent touchEndEvent(QEvent::TouchEnd, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointReleased, + touchPoints); + bool res; + + child1->weakpointer = &child1; + touchBeginEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && !child1); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && !child1); + touchEndEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchEndEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && !child1); + + child2->weakpointer = &child2; + touchBeginEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && child2); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); + QVERIFY(res && !touchUpdateEvent.isAccepted() && !child2); + touchEndEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchEndEvent); + QVERIFY(res && !touchUpdateEvent.isAccepted() && !child2); + + child3->weakpointer = &child3; + res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && child3); + res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); + QVERIFY(res && !touchUpdateEvent.isAccepted() && child3); + res = QApplication::sendEvent(view.viewport(), &touchEndEvent); + QVERIFY(res && !touchEndEvent.isAccepted() && !child3); + + delete root; + } +} + +void tst_QTouchEvent::deleteInRawEventTranslation() +{ + tst_QTouchEventWidget touchWidget; + touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); + touchWidget.setGeometry(100, 100, 300, 300); + + tst_QTouchEventWidget *leftWidget = new tst_QTouchEventWidget; + leftWidget->setParent(&touchWidget); + leftWidget->setAttribute(Qt::WA_AcceptTouchEvents); + leftWidget->setGeometry(0, 100, 100, 100); + leftWidget->deleteInTouchBegin = true; + leftWidget->show(); + + tst_QTouchEventWidget *centerWidget = new tst_QTouchEventWidget; + centerWidget->setParent(&touchWidget); + centerWidget->setAttribute(Qt::WA_AcceptTouchEvents); + centerWidget->setGeometry(100, 100, 100, 100); + centerWidget->deleteInTouchUpdate = true; + centerWidget->show(); + + tst_QTouchEventWidget *rightWidget = new tst_QTouchEventWidget; + rightWidget->setParent(&touchWidget); + rightWidget->setAttribute(Qt::WA_AcceptTouchEvents); + rightWidget->setGeometry(200, 100, 100, 100); + rightWidget->deleteInTouchEnd = true; + rightWidget->show(); + + QPointF leftPos = leftWidget->rect().center(); + QPointF centerPos = centerWidget->rect().center(); + QPointF rightPos = rightWidget->rect().center(); + QPointF leftScreenPos = leftWidget->mapToGlobal(leftPos.toPoint()); + QPointF centerScreenPos = centerWidget->mapToGlobal(centerPos.toPoint()); + QPointF rightScreenPos = rightWidget->mapToGlobal(rightPos.toPoint()); + QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + + QWeakPointer<QWidget> pl = leftWidget, pc = centerWidget, pr = rightWidget; + + QList<QTouchEvent::TouchPoint> rawTouchPoints; + rawTouchPoints.append(QTouchEvent::TouchPoint(0)); + rawTouchPoints.append(QTouchEvent::TouchPoint(1)); + rawTouchPoints.append(QTouchEvent::TouchPoint(2)); + rawTouchPoints[0].setState(Qt::TouchPointPressed); + rawTouchPoints[0].setScreenPos(leftScreenPos); + rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry)); + rawTouchPoints[1].setState(Qt::TouchPointPressed); + rawTouchPoints[1].setScreenPos(centerScreenPos); + rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry)); + rawTouchPoints[2].setState(Qt::TouchPointPressed); + rawTouchPoints[2].setScreenPos(rightScreenPos); + rawTouchPoints[2].setNormalizedPos(normalized(rawTouchPoints[2].pos(), screenGeometry)); + + // generate begin events on all widgets, the left widget should die + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); + QVERIFY(pl.isNull() && !pc.isNull() && !pr.isNull()); + + // generate update events on all widget, the center widget should die + rawTouchPoints[0].setState(Qt::TouchPointMoved); + rawTouchPoints[1].setState(Qt::TouchPointMoved); + rawTouchPoints[2].setState(Qt::TouchPointMoved); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); + + // generate end events on all widget, the right widget should die + rawTouchPoints[0].setState(Qt::TouchPointReleased); + rawTouchPoints[1].setState(Qt::TouchPointReleased); + rawTouchPoints[2].setState(Qt::TouchPointReleased); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); +} + QTEST_MAIN(tst_QTouchEvent) #include "tst_qtouchevent.moc" diff --git a/tests/benchmarks/qscriptengine/tst_qscriptengine.cpp b/tests/benchmarks/qscriptengine/tst_qscriptengine.cpp index 8d5f6e6..1c787e9 100644 --- a/tests/benchmarks/qscriptengine/tst_qscriptengine.cpp +++ b/tests/benchmarks/qscriptengine/tst_qscriptengine.cpp @@ -72,6 +72,8 @@ private slots: void toStringHandle(); void castValueToQreal(); void nativeCall(); + void translation_data(); + void translation(); }; tst_QScriptEngine::tst_QScriptEngine() @@ -259,5 +261,24 @@ void tst_QScriptEngine::nativeCall() } } +void tst_QScriptEngine::translation_data() +{ + QTest::addColumn<QString>("text"); + QTest::newRow("no translation") << "\"hello world\""; + QTest::newRow("qsTr") << "qsTr(\"hello world\")"; + QTest::newRow("qsTranslate") << "qsTranslate(\"\", \"hello world\")"; +} + +void tst_QScriptEngine::translation() +{ + QFETCH(QString, text); + QScriptEngine engine; + engine.installTranslatorFunctions(); + + QBENCHMARK { + (void)engine.evaluate(text); + } +} + QTEST_MAIN(tst_QScriptEngine) #include "tst_qscriptengine.moc" diff --git a/tests/manual/qwidget_zorder/main.cpp b/tests/manual/qwidget_zorder/main.cpp new file mode 100644 index 0000000..fe8e0a2 --- /dev/null +++ b/tests/manual/qwidget_zorder/main.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui> + +class Widget : public QWidget +{ + Q_OBJECT +public: + Widget() + { + QWidget *stackWidget = new QWidget; + stackWidget->setFixedSize(400, 300); + button = new QPushButton("pushbutton", stackWidget); + plainTextEdit = new QPlainTextEdit(stackWidget); + plainTextEdit->setWordWrapMode(QTextOption::NoWrap); + QString s = "foo bar bar foo foo bar bar foo"; + for (int i = 0; i < 10; ++i) { + plainTextEdit->appendPlainText(s); + s.remove(1, 2); + } + calendar = new QCalendarWidget(stackWidget); + button->move(10, 10); + button->resize(100, 100); + plainTextEdit->move(30, 70); + plainTextEdit->resize(100, 100); + calendar->move(80, 40); + + QWidget *buttonOps = new QWidget; + QVBoxLayout *l = new QVBoxLayout(buttonOps); + QPushButton *lower = new QPushButton("button: lower"); + connect(lower, SIGNAL(clicked()), button, SLOT(lower())); + l->addWidget(lower); + QPushButton *raise = new QPushButton("button: raise"); + connect(raise, SIGNAL(clicked()), button, SLOT(raise())); + l->addWidget(raise); + + lower = new QPushButton("calendar: lower"); + connect(lower, SIGNAL(clicked()), calendar, SLOT(lower())); + l->addWidget(lower); + raise = new QPushButton("calendar: raise"); + connect(raise, SIGNAL(clicked()), calendar, SLOT(raise())); + l->addWidget(raise); + QPushButton *stackUnder = new QPushButton("calendar: stack under textedit"); + connect(stackUnder, SIGNAL(clicked()), this, SLOT(stackCalendarUnderTextEdit())); + l->addWidget(stackUnder); + + lower = new QPushButton("lower textedit"); + connect(lower, SIGNAL(clicked()), plainTextEdit, SLOT(lower())); + l->addWidget(lower); + raise = new QPushButton("raise textedit"); + connect(raise, SIGNAL(clicked()), plainTextEdit, SLOT(raise())); + l->addWidget(raise); + + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->addWidget(buttonOps); + mainLayout->addWidget(stackWidget); + } + +private Q_SLOTS: + void stackCalendarUnderTextEdit() + { + calendar->stackUnder(plainTextEdit); + } + +private: + QPushButton *button; + QPlainTextEdit *plainTextEdit; + QCalendarWidget *calendar; +}; + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + Widget w; + w.show(); + return app.exec(); +} + +#include "main.moc" diff --git a/tests/manual/qwidget_zorder/qwidget_zorder.pro b/tests/manual/qwidget_zorder/qwidget_zorder.pro new file mode 100644 index 0000000..5526f91 --- /dev/null +++ b/tests/manual/qwidget_zorder/qwidget_zorder.pro @@ -0,0 +1,6 @@ +TEMPLATE = app +DEPENDPATH += . +INCLUDEPATH += . + +# Input +SOURCES += main.cpp |