Merge "Merge remote-tracking branch 'origin/5.4' into merge5.5" into refs/staging/5.5

This commit is contained in:
Allan Sandfeld Jensen 2015-05-08 15:29:43 +00:00 committed by The Qt Project
commit 9b2ee419b4
43 changed files with 576 additions and 303 deletions

107
dist/changes-5.4.2 vendored Normal file
View File

@ -0,0 +1,107 @@
Qt 5.4.2 is a bug-fix release. It maintains both forward and backward
compatibility (source and binary) with Qt 5.4.1. Compatibility with Qt
5.4.0 is also retained, except on Windows when using MSVC 2012 or MSVC
2013. See note below.
For more details, refer to the online documentation included in this
distribution. The documentation is also available online:
http://doc.qt.io/qt-5.4/
The Qt version 5.4 series is binary compatible with the 5.3.x series.
Applications compiled for 5.3 will continue to run with 5.4 with the
exception of on Windows when using MSVC 2012 or MSVC 2013. See note
below.
Some of the changes listed in this file include issue tracking numbers
corresponding to tasks in the Qt Bug Tracker:
http://bugreports.qt.io/
Each of these identifiers can be entered in the bug tracker to obtain more
information about a particular change.
****************************************************************************
* Important Behavior Changes *
****************************************************************************
- Restored binary compatibility with Qt 5.3.2 on Windows when using MSVC
2012 or MSVC 2013. This means that Qt 5.4.1 and 5.4.2 are no longer
binary compatible with Qt 5.4.0 when using either of those compilers.
- [QTBUG-42594] OS X binary package: fixed incorrect linking to libraries in
/opt/local/lib
- EXIF orientation is no longer applied to JPEG images on read. EXIF
orientation on JPEG was introduced in 5.4.0, but due to a bug the most
common EXIF-format (big-endian) was not working until 5.4.1. 5.4.2 restores the
behavior of 5.4.0 and earlier for most EXIF-tagged JPEGs.
EXIF orientation will be an opt-in starting with Qt 5.5.
****************************************************************************
* Library *
****************************************************************************
QtCore
------
- [QTBUG-43893] Fixed memory leak in qSetMessagePattern
- [QTBUG-43513] QXmlStreamReader: Correctly parse XML containing NUL bytes
in the input stream
- [QTBUG-43352] QTemporaryDirectory: Properly clean up in case of a failure
- [QTBUG-43827] Fixed regression in QSortFilterProxyModel which crashed when
sorting a tree model
QtGui
-----
- [QTBUG-44273] Fixed misplacement of outlined text with native text rendering
- [QTBUG-44147] Fixed VNC not working on some VNC servers
- [QTBUG-43850] Fixed crash with multi-threaded font usage
- [QTBUG-43850] Made the old harfbuzz fallback available at runtime
- Improvements to the experimental high-dpi support
- [QTBUG-43318] Better resolution of GLES 3 functions to avoid issues when
deploying on systems with GLES 2.0 only
QtWidgets
---------
- [QTBUG-43830] Fixed crash in stylesheets when styling QProgressBar
- [QTBUG-43663] QColorDialog: Don't lose focus while color picking
QtNetwork
---------
- [QTBUG-43793] Fixed disconnects of QSSLSocket after starting encryption
QtPrintSupport
--------------
- [QTBUG-43124] Fixed QPrinter::{width,height} return values
****************************************************************************
* Platform Specific Changes *
****************************************************************************
Android
-------
- [QTBUG-44648] Fixed rendering Chinese text on Android 5
Linux/XCB
---------
- [QTBUG-45071] Don't crash when resizing windows to bigger than 3840x2160
****************************************************************************
* Tools *
****************************************************************************
configure & build system
------------------------
- CMake-based projects using Qt will now always be built with -fPIE,
which fixes function pointer based QObject::connect() on ARM. This
is consistent with qmake
- [Android] Fixed compilation on armv5 with 4.9 toolchain
qmake
-----
- [VS] Fixed handling of files that are excluded from build
- [QTBUG-44413][VS] Fixed vcxproj generation for CONFIG-=flat, again
- [QTBUG-44595] Restored Qt 4 behavior of qtLibraryTarget()
- [QTBUG-45118][Windows] Fixed parallel build when using TYPELIBS
- [OS X/iOS] Fixed QMAKE_INFO_PLIST path resolution for shadow builds

View File

@ -43,7 +43,7 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -g
QMAKE_CFLAGS_DEBUG += -g QMAKE_CFLAGS_DEBUG += -g
QMAKE_CFLAGS_SHLIB += -fPIC QMAKE_CFLAGS_SHLIB += -fPIC
QMAKE_CFLAGS_STATIC_LIB += -fPIC QMAKE_CFLAGS_STATIC_LIB += -fPIC
QMAKE_CFLAGS_APP += -fPIE QMAKE_CFLAGS_APP += -fPIC
QMAKE_CFLAGS_ISYSTEM = -isystem QMAKE_CFLAGS_ISYSTEM = -isystem
QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses
QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden

View File

@ -23,7 +23,7 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -g
QMAKE_CFLAGS_DEBUG += -g QMAKE_CFLAGS_DEBUG += -g
QMAKE_CFLAGS_SHLIB += -fPIC -shared QMAKE_CFLAGS_SHLIB += -fPIC -shared
QMAKE_CFLAGS_STATIC_LIB += -fPIC QMAKE_CFLAGS_STATIC_LIB += -fPIC
QMAKE_CFLAGS_APP += -fPIE QMAKE_CFLAGS_APP += -fPIC
QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses
QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden
QMAKE_CFLAGS_SSE2 += -msse2 QMAKE_CFLAGS_SSE2 += -msse2

View File

@ -12,7 +12,7 @@ QMAKE_LEXFLAGS =
QMAKE_YACC = yacc QMAKE_YACC = yacc
QMAKE_YACCFLAGS = -d QMAKE_YACCFLAGS = -d
QMAKE_CFLAGS = QMAKE_CFLAGS =
QMAKE_CFLAGS_APP = -fPIE QMAKE_CFLAGS_APP = -fPIC
QMAKE_CFLAGS_DEPS = -M QMAKE_CFLAGS_DEPS = -M
QMAKE_CFLAGS_WARN_ON = -w1 -Wall -Wcheck -wd1572,873,2259,2261 QMAKE_CFLAGS_WARN_ON = -w1 -Wall -Wcheck -wd1572,873,2259,2261
QMAKE_CFLAGS_WARN_OFF = -w QMAKE_CFLAGS_WARN_OFF = -w

View File

@ -1092,7 +1092,9 @@ public class ExtractStyle {
{ {
try { try {
InsetDrawable d = (InsetDrawable)drawable; InsetDrawable d = (InsetDrawable)drawable;
Object mInsetStateObject = getAccessibleField(InsetDrawable.class, "mInsetState").get(d); // mInsetState changed to mState in Android 5.1 (22)
Object mInsetStateObject = getAccessibleField(InsetDrawable.class, (Build.VERSION.SDK_INT > 21) ? "mState"
: "mInsetState").get(d);
Rect _padding = new Rect(); Rect _padding = new Rect();
boolean hasPadding = d.getPadding(_padding); boolean hasPadding = d.getPadding(_padding);
return getDrawable(getAccessibleField(mInsetStateObject.getClass(), "mDrawable").get(mInsetStateObject), filename, hasPadding ? _padding : null); return getDrawable(getAccessibleField(mInsetStateObject.getClass(), "mDrawable").get(mInsetStateObject), filename, hasPadding ? _padding : null);

View File

@ -187,7 +187,7 @@ public class QtActivity extends Activity
QT_ANDROID_THEMES = new String[] {"Theme_Light"}; QT_ANDROID_THEMES = new String[] {"Theme_Light"};
QT_ANDROID_DEFAULT_THEME = "Theme_Light"; QT_ANDROID_DEFAULT_THEME = "Theme_Light";
} }
else if ((Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT <= 13) || Build.VERSION.SDK_INT == 21){ else if ((Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT <= 13) || Build.VERSION.SDK_INT >= 21){
QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"}; QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"};
QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light"; QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light";
} else { } else {

View File

@ -71,7 +71,7 @@ set(_qt5_corelib_extra_includes)
# macro to add it. # macro to add it.
set(Qt5_POSITION_INDEPENDENT_CODE True) set(Qt5_POSITION_INDEPENDENT_CODE True)
set_property(TARGET Qt5::Core PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE \"ON\") set_property(TARGET Qt5::Core PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE \"ON\")
set(Qt5Core_EXECUTABLE_COMPILE_FLAGS \"-fPIE\") set(Qt5Core_EXECUTABLE_COMPILE_FLAGS \"-fPIC\")
!!IF !isEmpty(QT_NAMESPACE) !!IF !isEmpty(QT_NAMESPACE)
list(APPEND Qt5Core_DEFINITIONS -DQT_NAMESPACE=$$QT_NAMESPACE) list(APPEND Qt5Core_DEFINITIONS -DQT_NAMESPACE=$$QT_NAMESPACE)

View File

@ -1062,9 +1062,9 @@ Q_CORE_EXPORT int qrand();
#define QT_MODULE(x) #define QT_MODULE(x)
#if !defined(QT_BOOTSTRAPPED) && defined(QT_REDUCE_RELOCATIONS) && defined(__ELF__) && !defined(__PIC__) && !defined(__PIE__) #if !defined(QT_BOOTSTRAPPED) && defined(QT_REDUCE_RELOCATIONS) && defined(__ELF__) && !defined(__PIC__)
# error "You must build your code with position independent code if Qt was built with -reduce-relocations. "\ # error "You must build your code with position independent code if Qt was built with -reduce-relocations. "\
"Compile your code with -fPIC or -fPIE." "Compile your code with -fPIC."
#endif #endif
namespace QtPrivate { namespace QtPrivate {

View File

@ -185,11 +185,11 @@ bool QLockFilePrivate::isApparentlyStale() const
{ {
qint64 pid; qint64 pid;
QString hostname, appname; QString hostname, appname;
if (!getLockInfo(&pid, &hostname, &appname)) if (getLockInfo(&pid, &hostname, &appname)) {
return false; if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) {
if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { if (::kill(pid, 0) == -1 && errno == ESRCH)
if (::kill(pid, 0) == -1 && errno == ESRCH) return true; // PID doesn't exist anymore
return true; // PID doesn't exist anymore }
} }
const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
return staleLockTime > 0 && age > staleLockTime; return staleLockTime > 0 && age > staleLockTime;

View File

@ -126,21 +126,21 @@ bool QLockFilePrivate::isApparentlyStale() const
{ {
qint64 pid; qint64 pid;
QString hostname, appname; QString hostname, appname;
if (!getLockInfo(&pid, &hostname, &appname))
return false;
// On WinRT there seems to be no way of obtaining information about other // On WinRT there seems to be no way of obtaining information about other
// processes due to sandboxing // processes due to sandboxing
#ifndef Q_OS_WINRT #ifndef Q_OS_WINRT
if (hostname == QString::fromLocal8Bit(localHostName())) { if (getLockInfo(&pid, &hostname, &appname)) {
HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); if (hostname == QString::fromLocal8Bit(localHostName())) {
if (!procHandle) HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
return true; if (!procHandle)
// We got a handle but check if process is still alive return true;
DWORD dwR = ::WaitForSingleObject(procHandle, 0); // We got a handle but check if process is still alive
::CloseHandle(procHandle); DWORD dwR = ::WaitForSingleObject(procHandle, 0);
if (dwR == WAIT_TIMEOUT) ::CloseHandle(procHandle);
return true; if (dwR == WAIT_TIMEOUT)
return true;
}
} }
#endif // !Q_OS_WINRT #endif // !Q_OS_WINRT
const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());

View File

@ -216,6 +216,11 @@ qint64 QNonContiguousByteDeviceByteArrayImpl::size()
return byteArray->size(); return byteArray->size();
} }
qint64 QNonContiguousByteDeviceByteArrayImpl::pos()
{
return currentPosition;
}
QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb) QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb)
: QNonContiguousByteDevice(), currentPosition(0) : QNonContiguousByteDevice(), currentPosition(0)
{ {
@ -253,6 +258,11 @@ bool QNonContiguousByteDeviceRingBufferImpl::atEnd()
return currentPosition >= size(); return currentPosition >= size();
} }
qint64 QNonContiguousByteDeviceRingBufferImpl::pos()
{
return currentPosition;
}
bool QNonContiguousByteDeviceRingBufferImpl::reset() bool QNonContiguousByteDeviceRingBufferImpl::reset()
{ {
currentPosition = 0; currentPosition = 0;
@ -381,6 +391,14 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::size()
return device->size() - initialPosition; return device->size() - initialPosition;
} }
qint64 QNonContiguousByteDeviceIoDeviceImpl::pos()
{
if (device->isSequential())
return -1;
return device->pos();
}
QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0) QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0)
{ {
byteDevice = bd; byteDevice = bd;

View File

@ -61,6 +61,7 @@ public:
virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0; virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0;
virtual bool advanceReadPointer(qint64 amount) = 0; virtual bool advanceReadPointer(qint64 amount) = 0;
virtual bool atEnd() = 0; virtual bool atEnd() = 0;
virtual qint64 pos() { return -1; }
virtual bool reset() = 0; virtual bool reset() = 0;
virtual qint64 size() = 0; virtual qint64 size() = 0;
@ -103,6 +104,7 @@ public:
bool atEnd() Q_DECL_OVERRIDE; bool atEnd() Q_DECL_OVERRIDE;
bool reset() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE;
qint64 size() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE;
qint64 pos() Q_DECL_OVERRIDE;
protected: protected:
QByteArray* byteArray; QByteArray* byteArray;
qint64 currentPosition; qint64 currentPosition;
@ -118,6 +120,7 @@ public:
bool atEnd() Q_DECL_OVERRIDE; bool atEnd() Q_DECL_OVERRIDE;
bool reset() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE;
qint64 size() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE;
qint64 pos() Q_DECL_OVERRIDE;
protected: protected:
QSharedPointer<QRingBuffer> ringBuffer; QSharedPointer<QRingBuffer> ringBuffer;
qint64 currentPosition; qint64 currentPosition;
@ -135,6 +138,7 @@ public:
bool atEnd() Q_DECL_OVERRIDE; bool atEnd() Q_DECL_OVERRIDE;
bool reset() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE;
qint64 size() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE;
qint64 pos() Q_DECL_OVERRIDE;
protected: protected:
QIODevice* device; QIODevice* device;
QByteArray* currentReadBuffer; QByteArray* currentReadBuffer;

View File

@ -36,7 +36,6 @@
#include <qdebug.h> #include <qdebug.h>
#include <qelapsedtimer.h> #include <qelapsedtimer.h>
#include <qeventloop.h> #include <qeventloop.h>
#include <qtimer.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -45,13 +44,11 @@ QWindowsPipeReader::QWindowsPipeReader(QObject *parent)
handle(INVALID_HANDLE_VALUE), handle(INVALID_HANDLE_VALUE),
readBufferMaxSize(0), readBufferMaxSize(0),
actualReadBufferSize(0), actualReadBufferSize(0),
stopped(true),
readSequenceStarted(false), readSequenceStarted(false),
emitReadyReadTimer(new QTimer(this)),
pipeBroken(false), pipeBroken(false),
readyReadEmitted(false) readyReadEmitted(false)
{ {
emitReadyReadTimer->setSingleShot(true);
connect(emitReadyReadTimer, SIGNAL(timeout()), SIGNAL(readyRead()));
dataReadNotifier = new QWinOverlappedIoNotifier(this); dataReadNotifier = new QWinOverlappedIoNotifier(this);
connect(dataReadNotifier, &QWinOverlappedIoNotifier::notified, this, &QWindowsPipeReader::notified); connect(dataReadNotifier, &QWinOverlappedIoNotifier::notified, this, &QWindowsPipeReader::notified);
} }
@ -73,12 +70,7 @@ static bool qt_cancelIo(HANDLE handle, OVERLAPPED *overlapped)
QWindowsPipeReader::~QWindowsPipeReader() QWindowsPipeReader::~QWindowsPipeReader()
{ {
if (readSequenceStarted) { stop();
if (qt_cancelIo(handle, &overlapped))
dataReadNotifier->waitForNotified(-1, &overlapped);
else
qErrnoWarning("QWindowsPipeReader: qt_cancelIo on handle %x failed.", handle);
}
} }
/*! /*!
@ -89,9 +81,9 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd)
readBuffer.clear(); readBuffer.clear();
actualReadBufferSize = 0; actualReadBufferSize = 0;
handle = hPipeReadEnd; handle = hPipeReadEnd;
ZeroMemory(&overlapped, sizeof(overlapped));
pipeBroken = false; pipeBroken = false;
readyReadEmitted = false; readyReadEmitted = false;
stopped = false;
if (hPipeReadEnd != INVALID_HANDLE_VALUE) { if (hPipeReadEnd != INVALID_HANDLE_VALUE) {
dataReadNotifier->setHandle(hPipeReadEnd); dataReadNotifier->setHandle(hPipeReadEnd);
dataReadNotifier->setEnabled(true); dataReadNotifier->setEnabled(true);
@ -100,13 +92,24 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd)
/*! /*!
Stops the asynchronous read sequence. Stops the asynchronous read sequence.
This function assumes that the file already has been closed. If the read sequence is running then the I/O operation is canceled.
It does not cancel any I/O operation.
*/ */
void QWindowsPipeReader::stop() void QWindowsPipeReader::stop()
{ {
dataReadNotifier->setEnabled(false); stopped = true;
if (readSequenceStarted) {
if (qt_cancelIo(handle, &overlapped)) {
dataReadNotifier->waitForNotified(-1, &overlapped);
} else {
const DWORD dwError = GetLastError();
if (dwError != ERROR_NOT_FOUND) {
qErrnoWarning(dwError, "QWindowsPipeReader: qt_cancelIo on handle %x failed.",
handle);
}
}
}
readSequenceStarted = false; readSequenceStarted = false;
dataReadNotifier->setEnabled(false);
handle = INVALID_HANDLE_VALUE; handle = INVALID_HANDLE_VALUE;
} }
@ -119,7 +122,7 @@ qint64 QWindowsPipeReader::bytesAvailable() const
} }
/*! /*!
Stops the asynchronous read sequence. Copies at most \c{maxlen} bytes from the internal read buffer to \c{data}.
*/ */
qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) qint64 QWindowsPipeReader::read(char *data, qint64 maxlen)
{ {
@ -147,9 +150,7 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen)
} }
if (!pipeBroken) { if (!pipeBroken) {
if (!actualReadBufferSize) if (!readSequenceStarted && !stopped)
emitReadyReadTimer->stop();
if (!readSequenceStarted)
startAsyncRead(); startAsyncRead();
if (readSoFar == 0) if (readSoFar == 0)
return -2; // signal EWOULDBLOCK return -2; // signal EWOULDBLOCK
@ -172,13 +173,41 @@ void QWindowsPipeReader::notified(quint32 numberOfBytesRead, quint32 errorCode,
{ {
if (&overlapped != notifiedOverlapped) if (&overlapped != notifiedOverlapped)
return; return;
if (!completeAsyncRead(numberOfBytesRead, errorCode)) {
switch (errorCode) {
case ERROR_SUCCESS:
break;
case ERROR_MORE_DATA:
// This is not an error. We're connected to a message mode
// pipe and the message didn't fit into the pipe's system
// buffer. We will read the remaining data in the next call.
break;
case ERROR_BROKEN_PIPE:
case ERROR_PIPE_NOT_CONNECTED:
pipeBroken = true; pipeBroken = true;
break;
default:
emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead"));
pipeBroken = true;
break;
}
readSequenceStarted = false;
// After the reader was stopped, the only reason why this function can be called is the
// completion of a cancellation. No signals should be emitted, and no new read sequence should
// be started in this case.
if (stopped)
return;
if (pipeBroken) {
emit pipeClosed(); emit pipeClosed();
return; return;
} }
actualReadBufferSize += numberOfBytesRead;
readBuffer.truncate(actualReadBufferSize);
startAsyncRead(); startAsyncRead();
emitReadyReadTimer->stop();
readyReadEmitted = true; readyReadEmitted = true;
emit readyRead(); emit readyRead();
} }
@ -206,6 +235,7 @@ void QWindowsPipeReader::startAsyncRead()
char *ptr = readBuffer.reserve(bytesToRead); char *ptr = readBuffer.reserve(bytesToRead);
readSequenceStarted = true; readSequenceStarted = true;
ZeroMemory(&overlapped, sizeof(overlapped));
if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) { if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) {
// We get notified by the QWinOverlappedIoNotifier - even in the synchronous case. // We get notified by the QWinOverlappedIoNotifier - even in the synchronous case.
return; return;
@ -239,38 +269,6 @@ void QWindowsPipeReader::startAsyncRead()
} }
} }
/*!
\internal
Sets the correct size of the read buffer after a read operation.
Returns \c false, if an error occurred or the connection dropped.
*/
bool QWindowsPipeReader::completeAsyncRead(DWORD bytesRead, DWORD errorCode)
{
readSequenceStarted = false;
switch (errorCode) {
case ERROR_SUCCESS:
break;
case ERROR_MORE_DATA:
// This is not an error. We're connected to a message mode
// pipe and the message didn't fit into the pipe's system
// buffer. We will read the remaining data in the next call.
break;
case ERROR_BROKEN_PIPE:
case ERROR_PIPE_NOT_CONNECTED:
return false;
default:
emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead"));
return false;
}
actualReadBufferSize += bytesRead;
readBuffer.truncate(actualReadBufferSize);
if (!emitReadyReadTimer->isActive())
emitReadyReadTimer->start();
return true;
}
/*! /*!
\internal \internal
Returns the number of available bytes in the pipe. Returns the number of available bytes in the pipe.

View File

@ -47,7 +47,6 @@
#include <qbytearray.h> #include <qbytearray.h>
#include <qobject.h> #include <qobject.h>
#include <qtimer.h>
#include <private/qringbuffer_p.h> #include <private/qringbuffer_p.h>
#include <qt_windows.h> #include <qt_windows.h>
@ -89,7 +88,6 @@ private Q_SLOTS:
void notified(quint32 numberOfBytesRead, quint32 errorCode, OVERLAPPED *notifiedOverlapped); void notified(quint32 numberOfBytesRead, quint32 errorCode, OVERLAPPED *notifiedOverlapped);
private: private:
bool completeAsyncRead(DWORD bytesRead, DWORD errorCode);
DWORD checkPipeState(); DWORD checkPipeState();
private: private:
@ -99,8 +97,8 @@ private:
qint64 readBufferMaxSize; qint64 readBufferMaxSize;
QRingBuffer readBuffer; QRingBuffer readBuffer;
int actualReadBufferSize; int actualReadBufferSize;
bool stopped;
bool readSequenceStarted; bool readSequenceStarted;
QTimer *emitReadyReadTimer;
bool pipeBroken; bool pipeBroken;
bool readyReadEmitted; bool readyReadEmitted;
}; };

View File

@ -714,7 +714,7 @@ public:
}; };
QJpegHandlerPrivate(QJpegHandler *qq) QJpegHandlerPrivate(QJpegHandler *qq)
: quality(75), exifOrientation(1), iod_src(0), : quality(75), iod_src(0),
rgb888ToRgb32ConverterPtr(qt_convert_rgb888_to_rgb32), state(Ready), optimize(false), progressive(false), q(qq) rgb888ToRgb32ConverterPtr(qt_convert_rgb888_to_rgb32), state(Ready), optimize(false), progressive(false), q(qq)
{} {}
@ -730,10 +730,8 @@ public:
bool readJpegHeader(QIODevice*); bool readJpegHeader(QIODevice*);
bool read(QImage *image); bool read(QImage *image);
void applyExifOrientation(QImage *image);
int quality; int quality;
int exifOrientation;
QVariant size; QVariant size;
QImage::Format format; QImage::Format format;
QSize scaledSize; QSize scaledSize;
@ -756,97 +754,6 @@ public:
QJpegHandler *q; QJpegHandler *q;
}; };
static bool readExifHeader(QDataStream &stream)
{
char prefix[6];
if (stream.readRawData(prefix, sizeof(prefix)) != sizeof(prefix))
return false;
if (prefix[0] != 'E' || prefix[1] != 'x' || prefix[2] != 'i' || prefix[3] != 'f' || prefix[4] != 0 || prefix[5] != 0)
return false;
return true;
}
/*
* Returns -1 on error
* Returns 0 if no Exif orientation was found
* Returns 1 orientation is horizontal (normal)
* Returns 2 mirror horizontal
* Returns 3 rotate 180
* Returns 4 mirror vertical
* Returns 5 mirror horizontal and rotate 270 CCW
* Returns 6 rotate 90 CW
* Returns 7 mirror horizontal and rotate 90 CW
* Returns 8 rotate 270 CW
*/
static int getExifOrientation(QByteArray &exifData)
{
QDataStream stream(&exifData, QIODevice::ReadOnly);
if (!readExifHeader(stream))
return -1;
quint16 val;
quint32 offset;
// read byte order marker
stream >> val;
if (val == 0x4949) // 'II' == Intel
stream.setByteOrder(QDataStream::LittleEndian);
else if (val == 0x4d4d) // 'MM' == Motorola
stream.setByteOrder(QDataStream::BigEndian);
else
return -1; // unknown byte order
// read size
stream >> val;
if (val != 0x2a)
return -1;
stream >> offset;
// we have already used 8 bytes of TIFF header
offset -= 8;
// read IFD
while (!stream.atEnd()) {
quint16 numEntries;
// skip offset bytes to get the next IFD
if (stream.skipRawData(offset) != (qint32)offset)
return -1;
stream >> numEntries;
for (;numEntries > 0; --numEntries) {
quint16 tag;
quint16 type;
quint32 components;
quint16 value;
quint16 dummy;
stream >> tag >> type >> components >> value >> dummy;
if (tag == 0x0112) { // Tag Exif.Image.Orientation
if (components !=1)
return -1;
if (type != 3) // we are expecting it to be an unsigned short
return -1;
if (value < 1 || value > 8) // check for valid range
return -1;
// It is possible to include the orientation multiple times.
// Right now the first value is returned.
return value;
}
}
// read offset to next IFD
stream >> offset;
if (offset == 0) // this is the last IFD
break;
}
// No Exif orientation was found
return 0;
}
/*! /*!
\internal \internal
*/ */
@ -866,7 +773,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
if (!setjmp(err.setjmp_buffer)) { if (!setjmp(err.setjmp_buffer)) {
jpeg_save_markers(&info, JPEG_COM, 0xFFFF); jpeg_save_markers(&info, JPEG_COM, 0xFFFF);
jpeg_save_markers(&info, JPEG_APP0+1, 0xFFFF); // Exif uses APP1 marker
(void) jpeg_read_header(&info, TRUE); (void) jpeg_read_header(&info, TRUE);
@ -878,8 +784,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
format = QImage::Format_Invalid; format = QImage::Format_Invalid;
read_jpeg_format(format, &info); read_jpeg_format(format, &info);
QByteArray exifData;
for (jpeg_saved_marker_ptr marker = info.marker_list; marker != NULL; marker = marker->next) { for (jpeg_saved_marker_ptr marker = info.marker_list; marker != NULL; marker = marker->next) {
if (marker->marker == JPEG_COM) { if (marker->marker == JPEG_COM) {
QString key, value; QString key, value;
@ -897,18 +801,9 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
description += key + QLatin1String(": ") + value.simplified(); description += key + QLatin1String(": ") + value.simplified();
readTexts.append(key); readTexts.append(key);
readTexts.append(value); readTexts.append(value);
} else if (marker->marker == JPEG_APP0+1) {
exifData.append((const char*)marker->data, marker->data_length);
} }
} }
if (exifData.size()) {
// Exif data present
int orientation = getExifOrientation(exifData);
if (orientation > 0)
exifOrientation = orientation;
}
state = ReadHeader; state = ReadHeader;
return true; return true;
} }
@ -922,48 +817,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
return true; return true;
} }
void QJpegHandlerPrivate::applyExifOrientation(QImage *image)
{
// This is not an optimized implementation, but easiest to maintain
QTransform transform;
switch (exifOrientation) {
case 1: // normal
break;
case 2: // mirror horizontal
*image = image->mirrored(true, false);
break;
case 3: // rotate 180
transform.rotate(180);
*image = image->transformed(transform);
break;
case 4: // mirror vertical
*image = image->mirrored(false, true);
break;
case 5: // mirror horizontal and rotate 270 CCW
*image = image->mirrored(true, false);
transform.rotate(270);
*image = image->transformed(transform);
break;
case 6: // rotate 90 CW
transform.rotate(90);
*image = image->transformed(transform);
break;
case 7: // mirror horizontal and rotate 90 CW
*image = image->mirrored(true, false);
transform.rotate(90);
*image = image->transformed(transform);
break;
case 8: // rotate 270 CW
transform.rotate(-90);
*image = image->transformed(transform);
break;
default:
qWarning("This should never happen");
}
exifOrientation = 1;
}
bool QJpegHandlerPrivate::read(QImage *image) bool QJpegHandlerPrivate::read(QImage *image)
{ {
if(state == Ready) if(state == Ready)
@ -975,7 +828,6 @@ bool QJpegHandlerPrivate::read(QImage *image)
if (success) { if (success) {
for (int i = 0; i < readTexts.size()-1; i+=2) for (int i = 0; i < readTexts.size()-1; i+=2)
image->setText(readTexts.at(i), readTexts.at(i+1)); image->setText(readTexts.at(i), readTexts.at(i+1));
applyExifOrientation(image);
state = Ready; state = Ready;
return true; return true;

View File

@ -106,15 +106,19 @@ void QHttpNetworkConnectionChannel::init()
socket->setProxy(QNetworkProxy::NoProxy); socket->setProxy(QNetworkProxy::NoProxy);
#endif #endif
// We want all signals (except the interactive ones) be connected as QueuedConnection
// because else we're falling into cases where we recurse back into the socket code
// and mess up the state. Always going to the event loop (and expecting that when reading/writing)
// is safer.
QObject::connect(socket, SIGNAL(bytesWritten(qint64)), QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_bytesWritten(qint64)), this, SLOT(_q_bytesWritten(qint64)),
Qt::DirectConnection); Qt::QueuedConnection);
QObject::connect(socket, SIGNAL(connected()), QObject::connect(socket, SIGNAL(connected()),
this, SLOT(_q_connected()), this, SLOT(_q_connected()),
Qt::DirectConnection); Qt::QueuedConnection);
QObject::connect(socket, SIGNAL(readyRead()), QObject::connect(socket, SIGNAL(readyRead()),
this, SLOT(_q_readyRead()), this, SLOT(_q_readyRead()),
Qt::DirectConnection); Qt::QueuedConnection);
// The disconnected() and error() signals may already come // The disconnected() and error() signals may already come
// while calling connectToHost(). // while calling connectToHost().
@ -143,7 +147,7 @@ void QHttpNetworkConnectionChannel::init()
// won't be a sslSocket if encrypt is false // won't be a sslSocket if encrypt is false
QObject::connect(sslSocket, SIGNAL(encrypted()), QObject::connect(sslSocket, SIGNAL(encrypted()),
this, SLOT(_q_encrypted()), this, SLOT(_q_encrypted()),
Qt::DirectConnection); Qt::QueuedConnection);
QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)), QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(_q_sslErrors(QList<QSslError>)), this, SLOT(_q_sslErrors(QList<QSslError>)),
Qt::DirectConnection); Qt::DirectConnection);
@ -152,7 +156,7 @@ void QHttpNetworkConnectionChannel::init()
Qt::DirectConnection); Qt::DirectConnection);
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)), QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
this, SLOT(_q_encryptedBytesWritten(qint64)), this, SLOT(_q_encryptedBytesWritten(qint64)),
Qt::DirectConnection); Qt::QueuedConnection);
if (ignoreAllSslErrors) if (ignoreAllSslErrors)
sslSocket->ignoreSslErrors(); sslSocket->ignoreSslErrors();
@ -189,8 +193,11 @@ void QHttpNetworkConnectionChannel::close()
// pendingEncrypt must only be true in between connected and encrypted states // pendingEncrypt must only be true in between connected and encrypted states
pendingEncrypt = false; pendingEncrypt = false;
if (socket) if (socket) {
// socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while
// there is no socket yet.
socket->close(); socket->close();
}
} }
@ -356,6 +363,14 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
} }
return false; return false;
} }
// This code path for ConnectedState
if (pendingEncrypt) {
// Let's only be really connected when we have received the encrypted() signal. Else the state machine seems to mess up
// and corrupt the things sent to the server.
return false;
}
return true; return true;
} }
@ -662,6 +677,12 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const
void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes) void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes)
{ {
Q_UNUSED(bytes); Q_UNUSED(bytes);
if (ssl) {
// In the SSL case we want to send data from encryptedBytesWritten signal since that one
// is the one going down to the actual network, not only into some SSL buffer.
return;
}
// bytes have been written to the socket. write even more of them :) // bytes have been written to the socket. write even more of them :)
if (isSocketWriting()) if (isSocketWriting())
sendRequest(); sendRequest();
@ -737,7 +758,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
// ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again! // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
//channels[i].reconnectAttempts = 2; //channels[i].reconnectAttempts = 2;
if (pendingEncrypt) { if (ssl || pendingEncrypt) { // FIXME: Didn't work properly with pendingEncrypt only, we should refactor this into an EncrypingState
#ifndef QT_NO_SSL #ifndef QT_NO_SSL
if (connection->sslContext().isNull()) { if (connection->sslContext().isNull()) {
// this socket is making the 1st handshake for this connection, // this socket is making the 1st handshake for this connection,

View File

@ -83,6 +83,8 @@ typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair;
class QHttpNetworkConnectionChannel : public QObject { class QHttpNetworkConnectionChannel : public QObject {
Q_OBJECT Q_OBJECT
public: public:
// TODO: Refactor this to add an EncryptingState (and remove pendingEncrypt).
// Also add an Unconnected state so IdleState does not have double meaning.
enum ChannelState { enum ChannelState {
IdleState = 0, // ready to send request IdleState = 0, // ready to send request
ConnectingState = 1, // connecting to host ConnectingState = 1, // connecting to host

View File

@ -368,6 +368,13 @@ bool QHttpProtocolHandler::sendRequest()
// nothing to read currently, break the loop // nothing to read currently, break the loop
break; break;
} else { } else {
if (m_channel->written != uploadByteDevice->pos()) {
// Sanity check. This was useful in tracking down an upload corruption.
qWarning() << "QHttpProtocolHandler: Internal error in sendRequest. Expected to write at position" << m_channel->written << "but read device is at" << uploadByteDevice->pos();
Q_ASSERT(m_channel->written == uploadByteDevice->pos());
m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::ProtocolFailure);
return false;
}
qint64 currentWriteSize = m_socket->write(readPointer, currentReadSize); qint64 currentWriteSize = m_socket->write(readPointer, currentReadSize);
if (currentWriteSize == -1 || currentWriteSize != currentReadSize) { if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
// socket broke down // socket broke down

View File

@ -189,6 +189,7 @@ protected:
QByteArray m_dataArray; QByteArray m_dataArray;
bool m_atEnd; bool m_atEnd;
qint64 m_size; qint64 m_size;
qint64 m_pos; // to match calls of haveDataSlot with the expected position
public: public:
QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s) QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s)
: QNonContiguousByteDevice(), : QNonContiguousByteDevice(),
@ -196,7 +197,8 @@ public:
m_amount(0), m_amount(0),
m_data(0), m_data(0),
m_atEnd(aE), m_atEnd(aE),
m_size(s) m_size(s),
m_pos(0)
{ {
} }
@ -204,6 +206,11 @@ public:
{ {
} }
qint64 pos() Q_DECL_OVERRIDE
{
return m_pos;
}
const char* readPointer(qint64 maximumLength, qint64 &len) Q_DECL_OVERRIDE const char* readPointer(qint64 maximumLength, qint64 &len) Q_DECL_OVERRIDE
{ {
if (m_amount > 0) { if (m_amount > 0) {
@ -231,11 +238,10 @@ public:
m_amount -= a; m_amount -= a;
m_data += a; m_data += a;
m_pos += a;
// To main thread to inform about our state // To main thread to inform about our state. The m_pos will be sent as a sanity check.
emit processedData(a); emit processedData(m_pos, a);
// FIXME possible optimization, already ask user thread for some data
return true; return true;
} }
@ -252,10 +258,21 @@ public:
{ {
m_amount = 0; m_amount = 0;
m_data = 0; m_data = 0;
m_dataArray.clear();
if (wantDataPending) {
// had requested the user thread to send some data (only 1 in-flight at any moment)
wantDataPending = false;
}
// Communicate as BlockingQueuedConnection // Communicate as BlockingQueuedConnection
bool b = false; bool b = false;
emit resetData(&b); emit resetData(&b);
if (b) {
// the reset succeeded, we're at pos 0 again
m_pos = 0;
// the HTTP code will anyway abort the request if !b.
}
return b; return b;
} }
@ -266,8 +283,13 @@ public:
public slots: public slots:
// From user thread: // From user thread:
void haveDataSlot(QByteArray dataArray, bool dataAtEnd, qint64 dataSize) void haveDataSlot(qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize)
{ {
if (pos != m_pos) {
// Sometimes when re-sending a request in the qhttpnetwork* layer there is a pending haveData from the
// user thread on the way to us. We need to ignore it since it is the data for the wrong(later) chunk.
return;
}
wantDataPending = false; wantDataPending = false;
m_dataArray = dataArray; m_dataArray = dataArray;
@ -287,7 +309,7 @@ signals:
// to main thread: // to main thread:
void wantData(qint64); void wantData(qint64);
void processedData(qint64); void processedData(qint64 pos, qint64 amount);
void resetData(bool *b); void resetData(bool *b);
}; };

View File

@ -424,6 +424,7 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate()
, synchronous(false) , synchronous(false)
, state(Idle) , state(Idle)
, statusCode(0) , statusCode(0)
, uploadByteDevicePosition(false)
, uploadDeviceChoking(false) , uploadDeviceChoking(false)
, outgoingData(0) , outgoingData(0)
, bytesUploaded(-1) , bytesUploaded(-1)
@ -867,9 +868,9 @@ void QNetworkReplyHttpImplPrivate::postRequest()
q, SLOT(uploadByteDeviceReadyReadSlot()), q, SLOT(uploadByteDeviceReadyReadSlot()),
Qt::QueuedConnection); Qt::QueuedConnection);
// From main thread to user thread: // From user thread to http thread:
QObject::connect(q, SIGNAL(haveUploadData(QByteArray,bool,qint64)), QObject::connect(q, SIGNAL(haveUploadData(qint64,QByteArray,bool,qint64)),
forwardUploadDevice, SLOT(haveDataSlot(QByteArray,bool,qint64)), Qt::QueuedConnection); forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,bool,qint64)), Qt::QueuedConnection);
QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()), QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()),
forwardUploadDevice, SIGNAL(readyRead()), forwardUploadDevice, SIGNAL(readyRead()),
Qt::QueuedConnection); Qt::QueuedConnection);
@ -877,8 +878,8 @@ void QNetworkReplyHttpImplPrivate::postRequest()
// From http thread to user thread: // From http thread to user thread:
QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)), QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)),
q, SLOT(wantUploadDataSlot(qint64))); q, SLOT(wantUploadDataSlot(qint64)));
QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)), QObject::connect(forwardUploadDevice,SIGNAL(processedData(qint64, qint64)),
q, SLOT(sentUploadDataSlot(qint64))); q, SLOT(sentUploadDataSlot(qint64,qint64)));
QObject::connect(forwardUploadDevice, SIGNAL(resetData(bool*)), QObject::connect(forwardUploadDevice, SIGNAL(resetData(bool*)),
q, SLOT(resetUploadDataSlot(bool*)), q, SLOT(resetUploadDataSlot(bool*)),
Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued! Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued!
@ -1278,12 +1279,22 @@ void QNetworkReplyHttpImplPrivate::replyPreSharedKeyAuthenticationRequiredSlot(Q
void QNetworkReplyHttpImplPrivate::resetUploadDataSlot(bool *r) void QNetworkReplyHttpImplPrivate::resetUploadDataSlot(bool *r)
{ {
*r = uploadByteDevice->reset(); *r = uploadByteDevice->reset();
if (*r) {
// reset our own position which is used for the inter-thread communication
uploadByteDevicePosition = 0;
}
} }
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread // Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 amount) void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 pos, qint64 amount)
{ {
if (uploadByteDevicePosition + amount != pos) {
// Sanity check, should not happen.
error(QNetworkReply::UnknownNetworkError, QString());
return;
}
uploadByteDevice->advanceReadPointer(amount); uploadByteDevice->advanceReadPointer(amount);
uploadByteDevicePosition += amount;
} }
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread // Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
@ -1308,7 +1319,7 @@ void QNetworkReplyHttpImplPrivate::wantUploadDataSlot(qint64 maxSize)
QByteArray dataArray(data, currentUploadDataLength); QByteArray dataArray(data, currentUploadDataLength);
// Communicate back to HTTP thread // Communicate back to HTTP thread
emit q->haveUploadData(dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size()); emit q->haveUploadData(uploadByteDevicePosition, dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size());
} }
void QNetworkReplyHttpImplPrivate::uploadByteDeviceReadyReadSlot() void QNetworkReplyHttpImplPrivate::uploadByteDeviceReadyReadSlot()

View File

@ -121,7 +121,7 @@ public:
Q_PRIVATE_SLOT(d_func(), void resetUploadDataSlot(bool *r)) Q_PRIVATE_SLOT(d_func(), void resetUploadDataSlot(bool *r))
Q_PRIVATE_SLOT(d_func(), void wantUploadDataSlot(qint64)) Q_PRIVATE_SLOT(d_func(), void wantUploadDataSlot(qint64))
Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64)) Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64,qint64))
Q_PRIVATE_SLOT(d_func(), void uploadByteDeviceReadyReadSlot()) Q_PRIVATE_SLOT(d_func(), void uploadByteDeviceReadyReadSlot())
Q_PRIVATE_SLOT(d_func(), void emitReplyUploadProgress(qint64, qint64)) Q_PRIVATE_SLOT(d_func(), void emitReplyUploadProgress(qint64, qint64))
Q_PRIVATE_SLOT(d_func(), void _q_cacheSaveDeviceAboutToClose()) Q_PRIVATE_SLOT(d_func(), void _q_cacheSaveDeviceAboutToClose())
@ -145,7 +145,7 @@ signals:
void startHttpRequestSynchronously(); void startHttpRequestSynchronously();
void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize); void haveUploadData(const qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize);
}; };
class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate
@ -196,6 +196,7 @@ public:
// upload // upload
QNonContiguousByteDevice* createUploadByteDevice(); QNonContiguousByteDevice* createUploadByteDevice();
QSharedPointer<QNonContiguousByteDevice> uploadByteDevice; QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
qint64 uploadByteDevicePosition;
bool uploadDeviceChoking; // if we couldn't readPointer() any data at the moment bool uploadDeviceChoking; // if we couldn't readPointer() any data at the moment
QIODevice *outgoingData; QIODevice *outgoingData;
QSharedPointer<QRingBuffer> outgoingDataBuffer; QSharedPointer<QRingBuffer> outgoingDataBuffer;
@ -285,7 +286,7 @@ public:
// From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread: // From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread:
void resetUploadDataSlot(bool *r); void resetUploadDataSlot(bool *r);
void wantUploadDataSlot(qint64); void wantUploadDataSlot(qint64);
void sentUploadDataSlot(qint64); void sentUploadDataSlot(qint64, qint64);
// From user's QNonContiguousByteDevice // From user's QNonContiguousByteDevice
void uploadByteDeviceReadyReadSlot(); void uploadByteDeviceReadyReadSlot();

View File

@ -688,8 +688,10 @@ void QCocoaWindow::setVisible(bool visible)
&& [m_nsWindow isKindOfClass:[NSPanel class]]) { && [m_nsWindow isKindOfClass:[NSPanel class]]) {
[(NSPanel *)m_nsWindow setWorksWhenModal:YES]; [(NSPanel *)m_nsWindow setWorksWhenModal:YES];
if (!(parentCocoaWindow && window()->transientParent()->isActive()) && window()->type() == Qt::Popup) { if (!(parentCocoaWindow && window()->transientParent()->isActive()) && window()->type() == Qt::Popup) {
monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDown handler:^(NSEvent *) { monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDownMask|NSMouseMovedMask handler:^(NSEvent *e) {
QWindowSystemInterface::handleMouseEvent(window(), QPointF(-1, -1), QPointF(window()->framePosition() - QPointF(1, 1)), Qt::LeftButton); QPointF localPoint = qt_mac_flipPoint([NSEvent mouseLocation]);
QWindowSystemInterface::handleMouseEvent(window(), window()->mapFromGlobal(localPoint.toPoint()), localPoint,
cocoaButton2QtButton([e buttonNumber]));
}]; }];
} }
} }

View File

@ -168,8 +168,20 @@ public:
QModelIndex index; QModelIndex index;
int col = -1; int col = -1;
int row = -1; int row = -1;
const QMimeData *mime = event->mimeData();
// Drag enter event shall always be accepted, if mime type and action match.
// Whether the data can actually be dropped will be checked in drag move.
if (event->type() == QEvent::DragEnter) {
const QStringList modelTypes = model->mimeTypes();
for (int i = 0; i < modelTypes.count(); ++i)
if (mime->hasFormat(modelTypes.at(i))
&& (event->dropAction() & model->supportedDropActions()))
return true;
}
if (dropOn(event, &row, &col, &index)) { if (dropOn(event, &row, &col, &index)) {
return model->canDropMimeData(event->mimeData(), return model->canDropMimeData(mime,
dragDropMode == QAbstractItemView::InternalMove ? Qt::MoveAction : event->dropAction(), dragDropMode == QAbstractItemView::InternalMove ? Qt::MoveAction : event->dropAction(),
row, col, index); row, col, index);
} }

View File

@ -4273,15 +4273,16 @@ void QApplicationPrivate::cleanupMultitouch_sys()
{ {
} }
QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos) QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, const QTouchEvent::TouchPoint &touchPoint)
{ {
const QPointF screenPos = touchPoint.screenPos();
int closestTouchPointId = -1; int closestTouchPointId = -1;
QObject *closestTarget = 0; QObject *closestTarget = 0;
qreal closestDistance = qreal(0.); qreal closestDistance = qreal(0.);
QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it = activeTouchPoints.constBegin(), QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it = activeTouchPoints.constBegin(),
ite = activeTouchPoints.constEnd(); ite = activeTouchPoints.constEnd();
while (it != ite) { while (it != ite) {
if (it.key().device == device) { if (it.key().device == device && it.key().touchPointId != touchPoint.id()) {
const QTouchEvent::TouchPoint &touchPoint = it->touchPoint; const QTouchEvent::TouchPoint &touchPoint = it->touchPoint;
qreal dx = screenPos.x() - touchPoint.screenPos().x(); qreal dx = screenPos.x() - touchPoint.screenPos().x();
qreal dy = screenPos.y() - touchPoint.screenPos().y(); qreal dy = screenPos.y() - touchPoint.screenPos().y();
@ -4337,7 +4338,7 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window,
} }
if (device->type() == QTouchDevice::TouchScreen) { if (device->type() == QTouchDevice::TouchScreen) {
QWidget *closestWidget = d->findClosestTouchPointTarget(device, touchPoint.screenPos()); QWidget *closestWidget = d->findClosestTouchPointTarget(device, touchPoint);
QWidget *widget = static_cast<QWidget *>(target.data()); QWidget *widget = static_cast<QWidget *>(target.data());
if (closestWidget if (closestWidget
&& (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) { && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) {

View File

@ -280,7 +280,7 @@ public:
void initializeMultitouch_sys(); void initializeMultitouch_sys();
void cleanupMultitouch(); void cleanupMultitouch();
void cleanupMultitouch_sys(); void cleanupMultitouch_sys();
QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos); QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QTouchEvent::TouchPoint &touchPoint);
void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint); void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint);
void removeTouchPoint(int touchPointId); void removeTouchPoint(int touchPointId);
static bool translateRawTouchEvent(QWidget *widget, static bool translateRawTouchEvent(QWidget *widget,

View File

@ -897,7 +897,7 @@ void QToolButton::setDefaultAction(QAction *action)
return; return;
if (!actions().contains(action)) if (!actions().contains(action))
addAction(action); addAction(action);
setText(action->iconText()); setText(action->text());
setIcon(action->icon()); setIcon(action->icon());
#ifndef QT_NO_TOOLTIP #ifndef QT_NO_TOOLTIP
setToolTip(action->toolTip()); setToolTip(action->toolTip());

View File

@ -62,6 +62,7 @@ private slots:
void staleLockRace(); void staleLockRace();
void noPermissions(); void noPermissions();
void noPermissionsWindows(); void noPermissionsWindows();
void corruptedLockFile();
public: public:
QString m_helperApp; QString m_helperApp;
@ -480,5 +481,21 @@ void tst_QLockFile::noPermissionsWindows()
QCOMPARE(int(lockFile.error()), int(QLockFile::PermissionError)); QCOMPARE(int(lockFile.error()), int(QLockFile::PermissionError));
} }
void tst_QLockFile::corruptedLockFile()
{
const QString fileName = dir.path() + "/corruptedLockFile";
{
// Create a empty file. Typically the result of a computer crash or hard disk full.
QFile file(fileName);
QVERIFY(file.open(QFile::WriteOnly));
}
QLockFile secondLock(fileName);
secondLock.setStaleLockTime(100);
QVERIFY(secondLock.tryLock(10000));
QCOMPARE(int(secondLock.error()), int(QLockFile::NoError));
}
QTEST_MAIN(tst_QLockFile) QTEST_MAIN(tst_QLockFile)
#include "tst_qlockfile.moc" #include "tst_qlockfile.moc"

View File

@ -87,8 +87,19 @@ static void addFixedTypes()
QTest::newRow("int64") << DBUS_TYPE_INT64_AS_STRING << true << true; QTest::newRow("int64") << DBUS_TYPE_INT64_AS_STRING << true << true;
QTest::newRow("uint64") << DBUS_TYPE_UINT64_AS_STRING << true << true; QTest::newRow("uint64") << DBUS_TYPE_UINT64_AS_STRING << true << true;
QTest::newRow("double") << DBUS_TYPE_DOUBLE_AS_STRING << true << true; QTest::newRow("double") << DBUS_TYPE_DOUBLE_AS_STRING << true << true;
#ifdef DBUS_TYPE_UNIX_FD_AS_STRING #ifdef DBUS_TYPE_UNIX_FD_AS_STRING
QTest::newRow("unixfd") << DBUS_TYPE_UNIX_FD_AS_STRING << true << true; # ifndef QT_LINKED_LIBDBUS
// We have got the macro from dbus_minimal_p.h, so we need to check if
// the library recognizes this as valid type first.
// The following function was added for Unix FD support, so if it is
// present, so is support for Unix FDs.
bool supportsUnixFds = qdbus_resolve_conditionally("dbus_connection_can_send_type");
# else
bool supportsUnixFds = true;
# endif
if (supportsUnixFds)
QTest::newRow("unixfd") << DBUS_TYPE_UNIX_FD_AS_STRING << true << true;
#endif #endif
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 910 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 910 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 995 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 987 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 991 B

View File

@ -181,9 +181,6 @@ private slots:
void invertPixelsRGB_data(); void invertPixelsRGB_data();
void invertPixelsRGB(); void invertPixelsRGB();
void exifOrientation_data();
void exifOrientation();
void cleanupFunctions(); void cleanupFunctions();
void devicePixelRatio(); void devicePixelRatio();
@ -2813,36 +2810,6 @@ void tst_QImage::invertPixelsRGB()
QCOMPARE(qBlue(pixel) >> 4, (255 - 96) >> 4); QCOMPARE(qBlue(pixel) >> 4, (255 - 96) >> 4);
} }
void tst_QImage::exifOrientation_data()
{
QTest::addColumn<QString>("fileName");
QTest::newRow("Orientation 1, Intel format") << m_prefix + "jpeg_exif_orientation_value_1.jpg";
QTest::newRow("Orientation 2, Intel format") << m_prefix + "jpeg_exif_orientation_value_2.jpg";
QTest::newRow("Orientation 3, Intel format") << m_prefix + "jpeg_exif_orientation_value_3.jpg";
QTest::newRow("Orientation 4, Intel format") << m_prefix + "jpeg_exif_orientation_value_4.jpg";
QTest::newRow("Orientation 5, Intel format") << m_prefix + "jpeg_exif_orientation_value_5.jpg";
QTest::newRow("Orientation 6, Intel format") << m_prefix + "jpeg_exif_orientation_value_6.jpg";
QTest::newRow("Orientation 6, Motorola format") << m_prefix + "jpeg_exif_orientation_value_6_motorola.jpg";
QTest::newRow("Orientation 7, Intel format") << m_prefix + "jpeg_exif_orientation_value_7.jpg";
QTest::newRow("Orientation 8, Intel format") << m_prefix + "jpeg_exif_orientation_value_8.jpg";
}
void tst_QImage::exifOrientation()
{
QFETCH(QString, fileName);
QImage img;
QRgb px;
QVERIFY(img.load(fileName));
px = img.pixel(0, 0);
QVERIFY(qRed(px) > 250 && qGreen(px) < 5 && qBlue(px) < 5);
px = img.pixel(img.width() - 1, 0);
QVERIFY(qRed(px) < 5 && qGreen(px) < 5 && qBlue(px) > 250);
}
static void cleanupFunction(void* info) static void cleanupFunction(void* info)
{ {
bool *called = static_cast<bool*>(info); bool *called = static_cast<bool*>(info);

View File

@ -456,6 +456,10 @@ private Q_SLOTS:
void putWithRateLimiting(); void putWithRateLimiting();
#ifndef QT_NO_SSL
void putWithServerClosingConnectionImmediately();
#endif
// NOTE: This test must be last! // NOTE: This test must be last!
void parentingRepliesToTheApp(); void parentingRepliesToTheApp();
private: private:
@ -4723,18 +4727,22 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
class SslServer : public QTcpServer { class SslServer : public QTcpServer {
Q_OBJECT Q_OBJECT
public: public:
SslServer() : socket(0) {}; SslServer() : socket(0), m_ssl(true) {}
void incomingConnection(qintptr socketDescriptor) { void incomingConnection(qintptr socketDescriptor) {
QSslSocket *serverSocket = new QSslSocket; QSslSocket *serverSocket = new QSslSocket;
serverSocket->setParent(this); serverSocket->setParent(this);
if (serverSocket->setSocketDescriptor(socketDescriptor)) { if (serverSocket->setSocketDescriptor(socketDescriptor)) {
connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
if (!m_ssl) {
emit newPlainConnection(serverSocket);
return;
}
QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath(); QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
if (testDataDir.isEmpty()) if (testDataDir.isEmpty())
testDataDir = QCoreApplication::applicationDirPath(); testDataDir = QCoreApplication::applicationDirPath();
connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot())); connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
serverSocket->setProtocol(QSsl::AnyProtocol); serverSocket->setProtocol(QSsl::AnyProtocol);
connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), serverSocket, SLOT(ignoreSslErrors())); connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), serverSocket, SLOT(ignoreSslErrors()));
serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem"); serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
@ -4745,11 +4753,12 @@ public:
} }
} }
signals: signals:
void newEncryptedConnection(); void newEncryptedConnection(QSslSocket *s);
void newPlainConnection(QSslSocket *s);
public slots: public slots:
void encryptedSlot() { void encryptedSlot() {
socket = (QSslSocket*) sender(); socket = (QSslSocket*) sender();
emit newEncryptedConnection(); emit newEncryptedConnection(socket);
} }
void readyReadSlot() { void readyReadSlot() {
// for the incoming sockets, not the server socket // for the incoming sockets, not the server socket
@ -4758,6 +4767,7 @@ public slots:
public: public:
QSslSocket *socket; QSslSocket *socket;
bool m_ssl;
}; };
// very similar to ioPostToHttpUploadProgress but for SSL // very similar to ioPostToHttpUploadProgress but for SSL
@ -4785,7 +4795,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
QNetworkReplyPtr reply(manager.post(request, sourceFile)); QNetworkReplyPtr reply(manager.post(request, sourceFile));
QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64))); QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); connect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop()));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply.data(), SLOT(ignoreSslErrors())); connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply.data(), SLOT(ignoreSslErrors()));
// get the request started and the incoming socket connected // get the request started and the incoming socket connected
@ -4793,7 +4803,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!QTestEventLoop::instance().timeout());
QTcpSocket *incomingSocket = server.socket; QTcpSocket *incomingSocket = server.socket;
QVERIFY(incomingSocket); QVERIFY(incomingSocket);
disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); disconnect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop()));
incomingSocket->setReadBufferSize(1*1024); incomingSocket->setReadBufferSize(1*1024);
@ -7963,6 +7973,159 @@ void tst_QNetworkReply::putWithRateLimiting()
} }
#ifndef QT_NO_SSL
class PutWithServerClosingConnectionImmediatelyHandler: public QObject
{
Q_OBJECT
public:
bool m_parsedHeaders;
QByteArray m_receivedData;
QByteArray m_expectedData;
QSslSocket *m_socket;
PutWithServerClosingConnectionImmediatelyHandler(QSslSocket *s, QByteArray expected) :m_parsedHeaders(false), m_expectedData(expected), m_socket(s)
{
m_socket->setParent(this);
connect(m_socket, SIGNAL(readyRead()), SLOT(readyReadSlot()));
connect(m_socket, SIGNAL(disconnected()), SLOT(disconnectedSlot()));
}
signals:
void correctFileUploadReceived();
void corruptFileUploadReceived();
public slots:
void closeDelayed() {
m_socket->close();
}
void readyReadSlot()
{
QByteArray data = m_socket->readAll();
m_receivedData += data;
if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) {
m_parsedHeaders = true;
QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency
// This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout
// In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload
// This test catches that.
}
}
void disconnectedSlot()
{
if (m_parsedHeaders) {
//qDebug() << m_receivedData.left(m_receivedData.indexOf("\r\n\r\n"));
m_receivedData = m_receivedData.mid(m_receivedData.indexOf("\r\n\r\n")+4); // check only actual data
}
if (m_receivedData.length() > 0 && !m_expectedData.startsWith(m_receivedData)) {
// We had received some data but it is corrupt!
qDebug() << "CORRUPT" << m_receivedData.count();
// Use this to track down the pattern of the corruption and conclude the source
// QFile a("/tmp/corrupt");
// a.open(QIODevice::WriteOnly);
// a.write(m_receivedData);
// a.close();
// QFile b("/tmp/correct");
// b.open(QIODevice::WriteOnly);
// b.write(m_expectedData);
// b.close();
//exit(1);
emit corruptFileUploadReceived();
} else {
emit correctFileUploadReceived();
}
}
};
class PutWithServerClosingConnectionImmediatelyServer: public SslServer
{
Q_OBJECT
public:
int m_correctUploads;
int m_corruptUploads;
int m_repliesFinished;
int m_expectedReplies;
QByteArray m_expectedData;
PutWithServerClosingConnectionImmediatelyServer() : SslServer(), m_correctUploads(0), m_corruptUploads(0), m_repliesFinished(0), m_expectedReplies(0)
{
QObject::connect(this, SIGNAL(newEncryptedConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*)));
QObject::connect(this, SIGNAL(newPlainConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*)));
}
public slots:
void createHandlerForConnection(QSslSocket* s) {
PutWithServerClosingConnectionImmediatelyHandler *handler = new PutWithServerClosingConnectionImmediatelyHandler(s, m_expectedData);
handler->setParent(this);
QObject::connect(handler, SIGNAL(correctFileUploadReceived()), this, SLOT(increaseCorrect()));
QObject::connect(handler, SIGNAL(corruptFileUploadReceived()), this, SLOT(increaseCorrupt()));
}
void increaseCorrect() {
m_correctUploads++;
}
void increaseCorrupt() {
m_corruptUploads++;
}
void replyFinished() {
m_repliesFinished++;
if (m_repliesFinished == m_expectedReplies) {
QTestEventLoop::instance().exitLoop();
}
}
};
void tst_QNetworkReply::putWithServerClosingConnectionImmediately()
{
const int numUploads = 40;
qint64 wantedSize = 512*1024; // 512 kB
QByteArray sourceFile;
for (int i = 0; i < wantedSize; ++i) {
sourceFile += (char)'a' +(i%26);
}
bool withSsl = false;
for (int s = 0; s <= 1; s++) {
withSsl = (s == 1);
// Test also needs to run several times because of 9c2ecf89
for (int j = 0; j < 20; j++) {
// emulate a minimal https server
PutWithServerClosingConnectionImmediatelyServer server;
server.m_ssl = withSsl;
server.m_expectedData = sourceFile;
server.m_expectedReplies = numUploads;
server.listen(QHostAddress(QHostAddress::LocalHost), 0);
for (int i = 0; i < numUploads; i++) {
// create the request
QUrl url = QUrl(QString("http%1://127.0.0.1:%2/file=%3").arg(withSsl ? "s" : "").arg(server.serverPort()).arg(i));
QNetworkRequest request(url);
QNetworkReply *reply = manager.put(request, sourceFile);
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply, SLOT(ignoreSslErrors()));
connect(reply, SIGNAL(finished()), &server, SLOT(replyFinished()));
reply->setParent(&server);
}
// get the request started and the incoming socket connected
QTestEventLoop::instance().enterLoop(10);
//qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" <<numUploads;
// Sanity check because ecause of 9c2ecf89 most replies will error out but we want to make sure at least some of them worked
QVERIFY(server.m_correctUploads > 5);
// Because actually important is that we don't get any corruption:
QCOMPARE(server.m_corruptUploads, 0);
server.close();
}
}
}
#endif
// NOTE: This test must be last testcase in tst_qnetworkreply! // NOTE: This test must be last testcase in tst_qnetworkreply!
void tst_QNetworkReply::parentingRepliesToTheApp() void tst_QNetworkReply::parentingRepliesToTheApp()

View File

@ -680,7 +680,7 @@ void tst_Moc::oldStyleCasts()
QStringList args; QStringList args;
args << "-c" << "-x" << "c++" << "-Wold-style-cast" << "-I" << "." args << "-c" << "-x" << "c++" << "-Wold-style-cast" << "-I" << "."
<< "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIE" << "-"; << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-";
proc.start("gcc", args); proc.start("gcc", args);
QVERIFY(proc.waitForStarted()); QVERIFY(proc.waitForStarted());
proc.write(mocOut); proc.write(mocOut);
@ -750,7 +750,7 @@ void tst_Moc::inputFileNameWithDotsButNoExtension()
QStringList args; QStringList args;
args << "-c" << "-x" << "c++" << "-I" << ".." args << "-c" << "-x" << "c++" << "-I" << ".."
<< "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIE" << "-"; << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-";
proc.start("gcc", args); proc.start("gcc", args);
QVERIFY(proc.waitForStarted()); QVERIFY(proc.waitForStarted());
proc.write(mocOut); proc.write(mocOut);
@ -1029,7 +1029,7 @@ void tst_Moc::ignoreOptionClashes()
// If -pthread wasn't ignored, it was parsed as a prefix of "thread/", which breaks compilation. // If -pthread wasn't ignored, it was parsed as a prefix of "thread/", which breaks compilation.
QStringList gccArgs; QStringList gccArgs;
gccArgs << "-c" << "-x" << "c++" << "-I" << ".." gccArgs << "-c" << "-x" << "c++" << "-I" << ".."
<< "-I" << qtIncludePath << "-I" << includeDir << "-o" << "/dev/null" << "-fPIE" << "-"; << "-I" << qtIncludePath << "-I" << includeDir << "-o" << "/dev/null" << "-fPIC" << "-";
proc.start("gcc", gccArgs); proc.start("gcc", gccArgs);
QVERIFY(proc.waitForStarted()); QVERIFY(proc.waitForStarted());
proc.write(mocOut); proc.write(mocOut);

View File

@ -436,6 +436,7 @@ private slots:
void grabKeyboard(); void grabKeyboard();
void touchEventSynthesizedMouseEvent(); void touchEventSynthesizedMouseEvent();
void touchUpdateOnNewTouch();
void styleSheetPropagation(); void styleSheetPropagation();
@ -9757,6 +9758,9 @@ class TouchMouseWidget : public QWidget {
public: public:
explicit TouchMouseWidget(QWidget *parent = 0) explicit TouchMouseWidget(QWidget *parent = 0)
: QWidget(parent), : QWidget(parent),
m_touchBeginCount(0),
m_touchUpdateCount(0),
m_touchEndCount(0),
m_touchEventCount(0), m_touchEventCount(0),
m_acceptTouch(false), m_acceptTouch(false),
m_mouseEventCount(0), m_mouseEventCount(0),
@ -9783,6 +9787,12 @@ protected:
case QEvent::TouchBegin: case QEvent::TouchBegin:
case QEvent::TouchUpdate: case QEvent::TouchUpdate:
case QEvent::TouchEnd: case QEvent::TouchEnd:
if (e->type() == QEvent::TouchBegin)
++m_touchBeginCount;
else if (e->type() == QEvent::TouchUpdate)
++m_touchUpdateCount;
else if (e->type() == QEvent::TouchEnd)
++m_touchEndCount;
++m_touchEventCount; ++m_touchEventCount;
if (m_acceptTouch) if (m_acceptTouch)
e->accept(); e->accept();
@ -9807,6 +9817,9 @@ protected:
} }
public: public:
int m_touchBeginCount;
int m_touchUpdateCount;
int m_touchEndCount;
int m_touchEventCount; int m_touchEventCount;
bool m_acceptTouch; bool m_acceptTouch;
int m_mouseEventCount; int m_mouseEventCount;
@ -9923,6 +9936,46 @@ void tst_QWidget::touchEventSynthesizedMouseEvent()
} }
} }
void tst_QWidget::touchUpdateOnNewTouch()
{
QTouchDevice *device = new QTouchDevice;
device->setType(QTouchDevice::TouchScreen);
QWindowSystemInterface::registerTouchDevice(device);
TouchMouseWidget widget;
widget.setAcceptTouch(true);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(new QWidget);
widget.setLayout(layout);
widget.show();
QWindow* window = widget.windowHandle();
QVERIFY(QTest::qWaitForWindowExposed(window));
QCOMPARE(widget.m_touchBeginCount, 0);
QCOMPARE(widget.m_touchUpdateCount, 0);
QCOMPARE(widget.m_touchEndCount, 0);
QTest::touchEvent(window, device).press(0, QPoint(20, 20), window);
QCOMPARE(widget.m_touchBeginCount, 1);
QCOMPARE(widget.m_touchUpdateCount, 0);
QCOMPARE(widget.m_touchEndCount, 0);
QTest::touchEvent(window, device).move(0, QPoint(25, 25), window);
QCOMPARE(widget.m_touchBeginCount, 1);
QCOMPARE(widget.m_touchUpdateCount, 1);
QCOMPARE(widget.m_touchEndCount, 0);
QTest::touchEvent(window, device).stationary(0).press(1, QPoint(40, 40), window);
QCOMPARE(widget.m_touchBeginCount, 1);
QCOMPARE(widget.m_touchUpdateCount, 2);
QCOMPARE(widget.m_touchEndCount, 0);
QTest::touchEvent(window, device).stationary(1).release(0, QPoint(25, 25), window);
QCOMPARE(widget.m_touchBeginCount, 1);
QCOMPARE(widget.m_touchUpdateCount, 3);
QCOMPARE(widget.m_touchEndCount, 0);
QTest::touchEvent(window, device).release(1, QPoint(40, 40), window);
QCOMPARE(widget.m_touchBeginCount, 1);
QCOMPARE(widget.m_touchUpdateCount, 3);
QCOMPARE(widget.m_touchEndCount, 1);
}
void tst_QWidget::styleSheetPropagation() void tst_QWidget::styleSheetPropagation()
{ {
QTableView tw; QTableView tw;

View File

@ -0,0 +1,2 @@
[task258920_mouseBorder]
osx

View File

@ -2,3 +2,5 @@
ubuntu-14.04 ubuntu-14.04
[taskQTBUG4965_escapeEaten] [taskQTBUG4965_escapeEaten]
ubuntu-14.04 ubuntu-14.04
[task256322_highlight]
osx