Merge "Merge remote-tracking branch 'origin/5.4' into merge5.5" into refs/staging/5.5
107
dist/changes-5.4.2
vendored
Normal 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
|
@ -43,7 +43,7 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -g
|
||||
QMAKE_CFLAGS_DEBUG += -g
|
||||
QMAKE_CFLAGS_SHLIB += -fPIC
|
||||
QMAKE_CFLAGS_STATIC_LIB += -fPIC
|
||||
QMAKE_CFLAGS_APP += -fPIE
|
||||
QMAKE_CFLAGS_APP += -fPIC
|
||||
QMAKE_CFLAGS_ISYSTEM = -isystem
|
||||
QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses
|
||||
QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden
|
||||
|
@ -23,7 +23,7 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -g
|
||||
QMAKE_CFLAGS_DEBUG += -g
|
||||
QMAKE_CFLAGS_SHLIB += -fPIC -shared
|
||||
QMAKE_CFLAGS_STATIC_LIB += -fPIC
|
||||
QMAKE_CFLAGS_APP += -fPIE
|
||||
QMAKE_CFLAGS_APP += -fPIC
|
||||
QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses
|
||||
QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden
|
||||
QMAKE_CFLAGS_SSE2 += -msse2
|
||||
|
@ -12,7 +12,7 @@ QMAKE_LEXFLAGS =
|
||||
QMAKE_YACC = yacc
|
||||
QMAKE_YACCFLAGS = -d
|
||||
QMAKE_CFLAGS =
|
||||
QMAKE_CFLAGS_APP = -fPIE
|
||||
QMAKE_CFLAGS_APP = -fPIC
|
||||
QMAKE_CFLAGS_DEPS = -M
|
||||
QMAKE_CFLAGS_WARN_ON = -w1 -Wall -Wcheck -wd1572,873,2259,2261
|
||||
QMAKE_CFLAGS_WARN_OFF = -w
|
||||
|
@ -1092,7 +1092,9 @@ public class ExtractStyle {
|
||||
{
|
||||
try {
|
||||
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();
|
||||
boolean hasPadding = d.getPadding(_padding);
|
||||
return getDrawable(getAccessibleField(mInsetStateObject.getClass(), "mDrawable").get(mInsetStateObject), filename, hasPadding ? _padding : null);
|
||||
|
@ -187,7 +187,7 @@ public class QtActivity extends Activity
|
||||
QT_ANDROID_THEMES = new String[] {"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_DEFAULT_THEME = "Theme_Holo_Light";
|
||||
} else {
|
||||
|
@ -71,7 +71,7 @@ set(_qt5_corelib_extra_includes)
|
||||
# macro to add it.
|
||||
set(Qt5_POSITION_INDEPENDENT_CODE True)
|
||||
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)
|
||||
list(APPEND Qt5Core_DEFINITIONS -DQT_NAMESPACE=$$QT_NAMESPACE)
|
||||
|
@ -1062,9 +1062,9 @@ Q_CORE_EXPORT int qrand();
|
||||
|
||||
#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. "\
|
||||
"Compile your code with -fPIC or -fPIE."
|
||||
"Compile your code with -fPIC."
|
||||
#endif
|
||||
|
||||
namespace QtPrivate {
|
||||
|
@ -185,12 +185,12 @@ bool QLockFilePrivate::isApparentlyStale() const
|
||||
{
|
||||
qint64 pid;
|
||||
QString hostname, appname;
|
||||
if (!getLockInfo(&pid, &hostname, &appname))
|
||||
return false;
|
||||
if (getLockInfo(&pid, &hostname, &appname)) {
|
||||
if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) {
|
||||
if (::kill(pid, 0) == -1 && errno == ESRCH)
|
||||
return true; // PID doesn't exist anymore
|
||||
}
|
||||
}
|
||||
const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
|
||||
return staleLockTime > 0 && age > staleLockTime;
|
||||
}
|
||||
|
@ -126,12 +126,11 @@ bool QLockFilePrivate::isApparentlyStale() const
|
||||
{
|
||||
qint64 pid;
|
||||
QString hostname, appname;
|
||||
if (!getLockInfo(&pid, &hostname, &appname))
|
||||
return false;
|
||||
|
||||
// On WinRT there seems to be no way of obtaining information about other
|
||||
// processes due to sandboxing
|
||||
#ifndef Q_OS_WINRT
|
||||
if (getLockInfo(&pid, &hostname, &appname)) {
|
||||
if (hostname == QString::fromLocal8Bit(localHostName())) {
|
||||
HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
if (!procHandle)
|
||||
@ -142,6 +141,7 @@ bool QLockFilePrivate::isApparentlyStale() const
|
||||
if (dwR == WAIT_TIMEOUT)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif // !Q_OS_WINRT
|
||||
const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
|
||||
return staleLockTime > 0 && age > staleLockTime;
|
||||
|
@ -216,6 +216,11 @@ qint64 QNonContiguousByteDeviceByteArrayImpl::size()
|
||||
return byteArray->size();
|
||||
}
|
||||
|
||||
qint64 QNonContiguousByteDeviceByteArrayImpl::pos()
|
||||
{
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb)
|
||||
: QNonContiguousByteDevice(), currentPosition(0)
|
||||
{
|
||||
@ -253,6 +258,11 @@ bool QNonContiguousByteDeviceRingBufferImpl::atEnd()
|
||||
return currentPosition >= size();
|
||||
}
|
||||
|
||||
qint64 QNonContiguousByteDeviceRingBufferImpl::pos()
|
||||
{
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
bool QNonContiguousByteDeviceRingBufferImpl::reset()
|
||||
{
|
||||
currentPosition = 0;
|
||||
@ -381,6 +391,14 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::size()
|
||||
return device->size() - initialPosition;
|
||||
}
|
||||
|
||||
qint64 QNonContiguousByteDeviceIoDeviceImpl::pos()
|
||||
{
|
||||
if (device->isSequential())
|
||||
return -1;
|
||||
|
||||
return device->pos();
|
||||
}
|
||||
|
||||
QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0)
|
||||
{
|
||||
byteDevice = bd;
|
||||
|
@ -61,6 +61,7 @@ public:
|
||||
virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0;
|
||||
virtual bool advanceReadPointer(qint64 amount) = 0;
|
||||
virtual bool atEnd() = 0;
|
||||
virtual qint64 pos() { return -1; }
|
||||
virtual bool reset() = 0;
|
||||
virtual qint64 size() = 0;
|
||||
|
||||
@ -103,6 +104,7 @@ public:
|
||||
bool atEnd() Q_DECL_OVERRIDE;
|
||||
bool reset() Q_DECL_OVERRIDE;
|
||||
qint64 size() Q_DECL_OVERRIDE;
|
||||
qint64 pos() Q_DECL_OVERRIDE;
|
||||
protected:
|
||||
QByteArray* byteArray;
|
||||
qint64 currentPosition;
|
||||
@ -118,6 +120,7 @@ public:
|
||||
bool atEnd() Q_DECL_OVERRIDE;
|
||||
bool reset() Q_DECL_OVERRIDE;
|
||||
qint64 size() Q_DECL_OVERRIDE;
|
||||
qint64 pos() Q_DECL_OVERRIDE;
|
||||
protected:
|
||||
QSharedPointer<QRingBuffer> ringBuffer;
|
||||
qint64 currentPosition;
|
||||
@ -135,6 +138,7 @@ public:
|
||||
bool atEnd() Q_DECL_OVERRIDE;
|
||||
bool reset() Q_DECL_OVERRIDE;
|
||||
qint64 size() Q_DECL_OVERRIDE;
|
||||
qint64 pos() Q_DECL_OVERRIDE;
|
||||
protected:
|
||||
QIODevice* device;
|
||||
QByteArray* currentReadBuffer;
|
||||
|
@ -36,7 +36,6 @@
|
||||
#include <qdebug.h>
|
||||
#include <qelapsedtimer.h>
|
||||
#include <qeventloop.h>
|
||||
#include <qtimer.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -45,13 +44,11 @@ QWindowsPipeReader::QWindowsPipeReader(QObject *parent)
|
||||
handle(INVALID_HANDLE_VALUE),
|
||||
readBufferMaxSize(0),
|
||||
actualReadBufferSize(0),
|
||||
stopped(true),
|
||||
readSequenceStarted(false),
|
||||
emitReadyReadTimer(new QTimer(this)),
|
||||
pipeBroken(false),
|
||||
readyReadEmitted(false)
|
||||
{
|
||||
emitReadyReadTimer->setSingleShot(true);
|
||||
connect(emitReadyReadTimer, SIGNAL(timeout()), SIGNAL(readyRead()));
|
||||
dataReadNotifier = new QWinOverlappedIoNotifier(this);
|
||||
connect(dataReadNotifier, &QWinOverlappedIoNotifier::notified, this, &QWindowsPipeReader::notified);
|
||||
}
|
||||
@ -73,12 +70,7 @@ static bool qt_cancelIo(HANDLE handle, OVERLAPPED *overlapped)
|
||||
|
||||
QWindowsPipeReader::~QWindowsPipeReader()
|
||||
{
|
||||
if (readSequenceStarted) {
|
||||
if (qt_cancelIo(handle, &overlapped))
|
||||
dataReadNotifier->waitForNotified(-1, &overlapped);
|
||||
else
|
||||
qErrnoWarning("QWindowsPipeReader: qt_cancelIo on handle %x failed.", handle);
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -89,9 +81,9 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd)
|
||||
readBuffer.clear();
|
||||
actualReadBufferSize = 0;
|
||||
handle = hPipeReadEnd;
|
||||
ZeroMemory(&overlapped, sizeof(overlapped));
|
||||
pipeBroken = false;
|
||||
readyReadEmitted = false;
|
||||
stopped = false;
|
||||
if (hPipeReadEnd != INVALID_HANDLE_VALUE) {
|
||||
dataReadNotifier->setHandle(hPipeReadEnd);
|
||||
dataReadNotifier->setEnabled(true);
|
||||
@ -100,13 +92,24 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd)
|
||||
|
||||
/*!
|
||||
Stops the asynchronous read sequence.
|
||||
This function assumes that the file already has been closed.
|
||||
It does not cancel any I/O operation.
|
||||
If the read sequence is running then the I/O operation is canceled.
|
||||
*/
|
||||
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;
|
||||
dataReadNotifier->setEnabled(false);
|
||||
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)
|
||||
{
|
||||
@ -147,9 +150,7 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen)
|
||||
}
|
||||
|
||||
if (!pipeBroken) {
|
||||
if (!actualReadBufferSize)
|
||||
emitReadyReadTimer->stop();
|
||||
if (!readSequenceStarted)
|
||||
if (!readSequenceStarted && !stopped)
|
||||
startAsyncRead();
|
||||
if (readSoFar == 0)
|
||||
return -2; // signal EWOULDBLOCK
|
||||
@ -172,13 +173,41 @@ void QWindowsPipeReader::notified(quint32 numberOfBytesRead, quint32 errorCode,
|
||||
{
|
||||
if (&overlapped != notifiedOverlapped)
|
||||
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;
|
||||
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();
|
||||
return;
|
||||
}
|
||||
|
||||
actualReadBufferSize += numberOfBytesRead;
|
||||
readBuffer.truncate(actualReadBufferSize);
|
||||
startAsyncRead();
|
||||
emitReadyReadTimer->stop();
|
||||
readyReadEmitted = true;
|
||||
emit readyRead();
|
||||
}
|
||||
@ -206,6 +235,7 @@ void QWindowsPipeReader::startAsyncRead()
|
||||
char *ptr = readBuffer.reserve(bytesToRead);
|
||||
|
||||
readSequenceStarted = true;
|
||||
ZeroMemory(&overlapped, sizeof(overlapped));
|
||||
if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) {
|
||||
// We get notified by the QWinOverlappedIoNotifier - even in the synchronous case.
|
||||
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
|
||||
Returns the number of available bytes in the pipe.
|
||||
|
@ -47,7 +47,6 @@
|
||||
|
||||
#include <qbytearray.h>
|
||||
#include <qobject.h>
|
||||
#include <qtimer.h>
|
||||
#include <private/qringbuffer_p.h>
|
||||
|
||||
#include <qt_windows.h>
|
||||
@ -89,7 +88,6 @@ private Q_SLOTS:
|
||||
void notified(quint32 numberOfBytesRead, quint32 errorCode, OVERLAPPED *notifiedOverlapped);
|
||||
|
||||
private:
|
||||
bool completeAsyncRead(DWORD bytesRead, DWORD errorCode);
|
||||
DWORD checkPipeState();
|
||||
|
||||
private:
|
||||
@ -99,8 +97,8 @@ private:
|
||||
qint64 readBufferMaxSize;
|
||||
QRingBuffer readBuffer;
|
||||
int actualReadBufferSize;
|
||||
bool stopped;
|
||||
bool readSequenceStarted;
|
||||
QTimer *emitReadyReadTimer;
|
||||
bool pipeBroken;
|
||||
bool readyReadEmitted;
|
||||
};
|
||||
|
@ -714,7 +714,7 @@ public:
|
||||
};
|
||||
|
||||
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)
|
||||
{}
|
||||
|
||||
@ -730,10 +730,8 @@ public:
|
||||
|
||||
bool readJpegHeader(QIODevice*);
|
||||
bool read(QImage *image);
|
||||
void applyExifOrientation(QImage *image);
|
||||
|
||||
int quality;
|
||||
int exifOrientation;
|
||||
QVariant size;
|
||||
QImage::Format format;
|
||||
QSize scaledSize;
|
||||
@ -756,97 +754,6 @@ public:
|
||||
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
|
||||
*/
|
||||
@ -866,7 +773,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
|
||||
|
||||
if (!setjmp(err.setjmp_buffer)) {
|
||||
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);
|
||||
|
||||
@ -878,8 +784,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
|
||||
format = QImage::Format_Invalid;
|
||||
read_jpeg_format(format, &info);
|
||||
|
||||
QByteArray exifData;
|
||||
|
||||
for (jpeg_saved_marker_ptr marker = info.marker_list; marker != NULL; marker = marker->next) {
|
||||
if (marker->marker == JPEG_COM) {
|
||||
QString key, value;
|
||||
@ -897,18 +801,9 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
|
||||
description += key + QLatin1String(": ") + value.simplified();
|
||||
readTexts.append(key);
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
@ -922,48 +817,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
|
||||
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)
|
||||
{
|
||||
if(state == Ready)
|
||||
@ -975,7 +828,6 @@ bool QJpegHandlerPrivate::read(QImage *image)
|
||||
if (success) {
|
||||
for (int i = 0; i < readTexts.size()-1; i+=2)
|
||||
image->setText(readTexts.at(i), readTexts.at(i+1));
|
||||
applyExifOrientation(image);
|
||||
|
||||
state = Ready;
|
||||
return true;
|
||||
|
@ -106,15 +106,19 @@ void QHttpNetworkConnectionChannel::init()
|
||||
socket->setProxy(QNetworkProxy::NoProxy);
|
||||
#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)),
|
||||
this, SLOT(_q_bytesWritten(qint64)),
|
||||
Qt::DirectConnection);
|
||||
Qt::QueuedConnection);
|
||||
QObject::connect(socket, SIGNAL(connected()),
|
||||
this, SLOT(_q_connected()),
|
||||
Qt::DirectConnection);
|
||||
Qt::QueuedConnection);
|
||||
QObject::connect(socket, SIGNAL(readyRead()),
|
||||
this, SLOT(_q_readyRead()),
|
||||
Qt::DirectConnection);
|
||||
Qt::QueuedConnection);
|
||||
|
||||
// The disconnected() and error() signals may already come
|
||||
// while calling connectToHost().
|
||||
@ -143,7 +147,7 @@ void QHttpNetworkConnectionChannel::init()
|
||||
// won't be a sslSocket if encrypt is false
|
||||
QObject::connect(sslSocket, SIGNAL(encrypted()),
|
||||
this, SLOT(_q_encrypted()),
|
||||
Qt::DirectConnection);
|
||||
Qt::QueuedConnection);
|
||||
QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
|
||||
this, SLOT(_q_sslErrors(QList<QSslError>)),
|
||||
Qt::DirectConnection);
|
||||
@ -152,7 +156,7 @@ void QHttpNetworkConnectionChannel::init()
|
||||
Qt::DirectConnection);
|
||||
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
|
||||
this, SLOT(_q_encryptedBytesWritten(qint64)),
|
||||
Qt::DirectConnection);
|
||||
Qt::QueuedConnection);
|
||||
|
||||
if (ignoreAllSslErrors)
|
||||
sslSocket->ignoreSslErrors();
|
||||
@ -189,8 +193,11 @@ void QHttpNetworkConnectionChannel::close()
|
||||
// pendingEncrypt must only be true in between connected and encrypted states
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -356,6 +363,14 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -662,6 +677,12 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const
|
||||
void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 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 :)
|
||||
if (isSocketWriting())
|
||||
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!
|
||||
//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
|
||||
if (connection->sslContext().isNull()) {
|
||||
// this socket is making the 1st handshake for this connection,
|
||||
|
@ -83,6 +83,8 @@ typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair;
|
||||
class QHttpNetworkConnectionChannel : public QObject {
|
||||
Q_OBJECT
|
||||
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 {
|
||||
IdleState = 0, // ready to send request
|
||||
ConnectingState = 1, // connecting to host
|
||||
|
@ -368,6 +368,13 @@ bool QHttpProtocolHandler::sendRequest()
|
||||
// nothing to read currently, break the loop
|
||||
break;
|
||||
} 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);
|
||||
if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
|
||||
// socket broke down
|
||||
|
@ -189,6 +189,7 @@ protected:
|
||||
QByteArray m_dataArray;
|
||||
bool m_atEnd;
|
||||
qint64 m_size;
|
||||
qint64 m_pos; // to match calls of haveDataSlot with the expected position
|
||||
public:
|
||||
QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s)
|
||||
: QNonContiguousByteDevice(),
|
||||
@ -196,7 +197,8 @@ public:
|
||||
m_amount(0),
|
||||
m_data(0),
|
||||
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
|
||||
{
|
||||
if (m_amount > 0) {
|
||||
@ -231,11 +238,10 @@ public:
|
||||
|
||||
m_amount -= a;
|
||||
m_data += a;
|
||||
m_pos += a;
|
||||
|
||||
// To main thread to inform about our state
|
||||
emit processedData(a);
|
||||
|
||||
// FIXME possible optimization, already ask user thread for some data
|
||||
// To main thread to inform about our state. The m_pos will be sent as a sanity check.
|
||||
emit processedData(m_pos, a);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -252,10 +258,21 @@ public:
|
||||
{
|
||||
m_amount = 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
|
||||
bool b = false;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -266,8 +283,13 @@ public:
|
||||
|
||||
public slots:
|
||||
// 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;
|
||||
|
||||
m_dataArray = dataArray;
|
||||
@ -287,7 +309,7 @@ signals:
|
||||
|
||||
// to main thread:
|
||||
void wantData(qint64);
|
||||
void processedData(qint64);
|
||||
void processedData(qint64 pos, qint64 amount);
|
||||
void resetData(bool *b);
|
||||
};
|
||||
|
||||
|
@ -424,6 +424,7 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate()
|
||||
, synchronous(false)
|
||||
, state(Idle)
|
||||
, statusCode(0)
|
||||
, uploadByteDevicePosition(false)
|
||||
, uploadDeviceChoking(false)
|
||||
, outgoingData(0)
|
||||
, bytesUploaded(-1)
|
||||
@ -867,9 +868,9 @@ void QNetworkReplyHttpImplPrivate::postRequest()
|
||||
q, SLOT(uploadByteDeviceReadyReadSlot()),
|
||||
Qt::QueuedConnection);
|
||||
|
||||
// From main thread to user thread:
|
||||
QObject::connect(q, SIGNAL(haveUploadData(QByteArray,bool,qint64)),
|
||||
forwardUploadDevice, SLOT(haveDataSlot(QByteArray,bool,qint64)), Qt::QueuedConnection);
|
||||
// From user thread to http thread:
|
||||
QObject::connect(q, SIGNAL(haveUploadData(qint64,QByteArray,bool,qint64)),
|
||||
forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,bool,qint64)), Qt::QueuedConnection);
|
||||
QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()),
|
||||
forwardUploadDevice, SIGNAL(readyRead()),
|
||||
Qt::QueuedConnection);
|
||||
@ -877,8 +878,8 @@ void QNetworkReplyHttpImplPrivate::postRequest()
|
||||
// From http thread to user thread:
|
||||
QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)),
|
||||
q, SLOT(wantUploadDataSlot(qint64)));
|
||||
QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)),
|
||||
q, SLOT(sentUploadDataSlot(qint64)));
|
||||
QObject::connect(forwardUploadDevice,SIGNAL(processedData(qint64, qint64)),
|
||||
q, SLOT(sentUploadDataSlot(qint64,qint64)));
|
||||
QObject::connect(forwardUploadDevice, SIGNAL(resetData(bool*)),
|
||||
q, SLOT(resetUploadDataSlot(bool*)),
|
||||
Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued!
|
||||
@ -1278,12 +1279,22 @@ void QNetworkReplyHttpImplPrivate::replyPreSharedKeyAuthenticationRequiredSlot(Q
|
||||
void QNetworkReplyHttpImplPrivate::resetUploadDataSlot(bool *r)
|
||||
{
|
||||
*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
|
||||
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);
|
||||
uploadByteDevicePosition += amount;
|
||||
}
|
||||
|
||||
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
|
||||
@ -1308,7 +1319,7 @@ void QNetworkReplyHttpImplPrivate::wantUploadDataSlot(qint64 maxSize)
|
||||
QByteArray dataArray(data, currentUploadDataLength);
|
||||
|
||||
// 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()
|
||||
|
@ -121,7 +121,7 @@ public:
|
||||
|
||||
Q_PRIVATE_SLOT(d_func(), void resetUploadDataSlot(bool *r))
|
||||
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 emitReplyUploadProgress(qint64, qint64))
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_cacheSaveDeviceAboutToClose())
|
||||
@ -145,7 +145,7 @@ signals:
|
||||
|
||||
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
|
||||
@ -196,6 +196,7 @@ public:
|
||||
// upload
|
||||
QNonContiguousByteDevice* createUploadByteDevice();
|
||||
QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
|
||||
qint64 uploadByteDevicePosition;
|
||||
bool uploadDeviceChoking; // if we couldn't readPointer() any data at the moment
|
||||
QIODevice *outgoingData;
|
||||
QSharedPointer<QRingBuffer> outgoingDataBuffer;
|
||||
@ -285,7 +286,7 @@ public:
|
||||
// From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread:
|
||||
void resetUploadDataSlot(bool *r);
|
||||
void wantUploadDataSlot(qint64);
|
||||
void sentUploadDataSlot(qint64);
|
||||
void sentUploadDataSlot(qint64, qint64);
|
||||
|
||||
// From user's QNonContiguousByteDevice
|
||||
void uploadByteDeviceReadyReadSlot();
|
||||
|
@ -688,8 +688,10 @@ void QCocoaWindow::setVisible(bool visible)
|
||||
&& [m_nsWindow isKindOfClass:[NSPanel class]]) {
|
||||
[(NSPanel *)m_nsWindow setWorksWhenModal:YES];
|
||||
if (!(parentCocoaWindow && window()->transientParent()->isActive()) && window()->type() == Qt::Popup) {
|
||||
monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDown handler:^(NSEvent *) {
|
||||
QWindowSystemInterface::handleMouseEvent(window(), QPointF(-1, -1), QPointF(window()->framePosition() - QPointF(1, 1)), Qt::LeftButton);
|
||||
monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDownMask|NSMouseMovedMask handler:^(NSEvent *e) {
|
||||
QPointF localPoint = qt_mac_flipPoint([NSEvent mouseLocation]);
|
||||
QWindowSystemInterface::handleMouseEvent(window(), window()->mapFromGlobal(localPoint.toPoint()), localPoint,
|
||||
cocoaButton2QtButton([e buttonNumber]));
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
@ -168,8 +168,20 @@ public:
|
||||
QModelIndex index;
|
||||
int col = -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)) {
|
||||
return model->canDropMimeData(event->mimeData(),
|
||||
return model->canDropMimeData(mime,
|
||||
dragDropMode == QAbstractItemView::InternalMove ? Qt::MoveAction : event->dropAction(),
|
||||
row, col, index);
|
||||
}
|
||||
|
@ -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;
|
||||
QObject *closestTarget = 0;
|
||||
qreal closestDistance = qreal(0.);
|
||||
QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it = activeTouchPoints.constBegin(),
|
||||
ite = activeTouchPoints.constEnd();
|
||||
while (it != ite) {
|
||||
if (it.key().device == device) {
|
||||
if (it.key().device == device && it.key().touchPointId != touchPoint.id()) {
|
||||
const QTouchEvent::TouchPoint &touchPoint = it->touchPoint;
|
||||
qreal dx = screenPos.x() - touchPoint.screenPos().x();
|
||||
qreal dy = screenPos.y() - touchPoint.screenPos().y();
|
||||
@ -4337,7 +4338,7 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window,
|
||||
}
|
||||
|
||||
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());
|
||||
if (closestWidget
|
||||
&& (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) {
|
||||
|
@ -280,7 +280,7 @@ public:
|
||||
void initializeMultitouch_sys();
|
||||
void cleanupMultitouch();
|
||||
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 removeTouchPoint(int touchPointId);
|
||||
static bool translateRawTouchEvent(QWidget *widget,
|
||||
|
@ -897,7 +897,7 @@ void QToolButton::setDefaultAction(QAction *action)
|
||||
return;
|
||||
if (!actions().contains(action))
|
||||
addAction(action);
|
||||
setText(action->iconText());
|
||||
setText(action->text());
|
||||
setIcon(action->icon());
|
||||
#ifndef QT_NO_TOOLTIP
|
||||
setToolTip(action->toolTip());
|
||||
|
@ -62,6 +62,7 @@ private slots:
|
||||
void staleLockRace();
|
||||
void noPermissions();
|
||||
void noPermissionsWindows();
|
||||
void corruptedLockFile();
|
||||
|
||||
public:
|
||||
QString m_helperApp;
|
||||
@ -480,5 +481,21 @@ void tst_QLockFile::noPermissionsWindows()
|
||||
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)
|
||||
#include "tst_qlockfile.moc"
|
||||
|
@ -87,7 +87,18 @@ static void addFixedTypes()
|
||||
QTest::newRow("int64") << DBUS_TYPE_INT64_AS_STRING << true << true;
|
||||
QTest::newRow("uint64") << DBUS_TYPE_UINT64_AS_STRING << true << true;
|
||||
QTest::newRow("double") << DBUS_TYPE_DOUBLE_AS_STRING << true << true;
|
||||
|
||||
#ifdef DBUS_TYPE_UNIX_FD_AS_STRING
|
||||
# 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
|
||||
}
|
||||
|
Before Width: | Height: | Size: 910 B |
Before Width: | Height: | Size: 910 B |
Before Width: | Height: | Size: 988 B |
Before Width: | Height: | Size: 995 B |
Before Width: | Height: | Size: 912 B |
Before Width: | Height: | Size: 911 B |
Before Width: | Height: | Size: 911 B |
Before Width: | Height: | Size: 987 B |
Before Width: | Height: | Size: 991 B |
@ -181,9 +181,6 @@ private slots:
|
||||
void invertPixelsRGB_data();
|
||||
void invertPixelsRGB();
|
||||
|
||||
void exifOrientation_data();
|
||||
void exifOrientation();
|
||||
|
||||
void cleanupFunctions();
|
||||
|
||||
void devicePixelRatio();
|
||||
@ -2813,36 +2810,6 @@ void tst_QImage::invertPixelsRGB()
|
||||
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)
|
||||
{
|
||||
bool *called = static_cast<bool*>(info);
|
||||
|
@ -456,6 +456,10 @@ private Q_SLOTS:
|
||||
|
||||
void putWithRateLimiting();
|
||||
|
||||
#ifndef QT_NO_SSL
|
||||
void putWithServerClosingConnectionImmediately();
|
||||
#endif
|
||||
|
||||
// NOTE: This test must be last!
|
||||
void parentingRepliesToTheApp();
|
||||
private:
|
||||
@ -4723,18 +4727,22 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
|
||||
class SslServer : public QTcpServer {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SslServer() : socket(0) {};
|
||||
SslServer() : socket(0), m_ssl(true) {}
|
||||
void incomingConnection(qintptr socketDescriptor) {
|
||||
QSslSocket *serverSocket = new QSslSocket;
|
||||
serverSocket->setParent(this);
|
||||
|
||||
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();
|
||||
if (testDataDir.isEmpty())
|
||||
testDataDir = QCoreApplication::applicationDirPath();
|
||||
|
||||
connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
|
||||
connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
|
||||
serverSocket->setProtocol(QSsl::AnyProtocol);
|
||||
connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), serverSocket, SLOT(ignoreSslErrors()));
|
||||
serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
|
||||
@ -4745,11 +4753,12 @@ public:
|
||||
}
|
||||
}
|
||||
signals:
|
||||
void newEncryptedConnection();
|
||||
void newEncryptedConnection(QSslSocket *s);
|
||||
void newPlainConnection(QSslSocket *s);
|
||||
public slots:
|
||||
void encryptedSlot() {
|
||||
socket = (QSslSocket*) sender();
|
||||
emit newEncryptedConnection();
|
||||
emit newEncryptedConnection(socket);
|
||||
}
|
||||
void readyReadSlot() {
|
||||
// for the incoming sockets, not the server socket
|
||||
@ -4758,6 +4767,7 @@ public slots:
|
||||
|
||||
public:
|
||||
QSslSocket *socket;
|
||||
bool m_ssl;
|
||||
};
|
||||
|
||||
// very similar to ioPostToHttpUploadProgress but for SSL
|
||||
@ -4785,7 +4795,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
|
||||
QNetworkReplyPtr reply(manager.post(request, sourceFile));
|
||||
|
||||
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()));
|
||||
|
||||
// get the request started and the incoming socket connected
|
||||
@ -4793,7 +4803,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QTcpSocket *incomingSocket = server.socket;
|
||||
QVERIFY(incomingSocket);
|
||||
disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
disconnect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
|
||||
|
||||
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!
|
||||
void tst_QNetworkReply::parentingRepliesToTheApp()
|
||||
|
@ -680,7 +680,7 @@ void tst_Moc::oldStyleCasts()
|
||||
|
||||
QStringList args;
|
||||
args << "-c" << "-x" << "c++" << "-Wold-style-cast" << "-I" << "."
|
||||
<< "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIE" << "-";
|
||||
<< "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-";
|
||||
proc.start("gcc", args);
|
||||
QVERIFY(proc.waitForStarted());
|
||||
proc.write(mocOut);
|
||||
@ -750,7 +750,7 @@ void tst_Moc::inputFileNameWithDotsButNoExtension()
|
||||
|
||||
QStringList args;
|
||||
args << "-c" << "-x" << "c++" << "-I" << ".."
|
||||
<< "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIE" << "-";
|
||||
<< "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-";
|
||||
proc.start("gcc", args);
|
||||
QVERIFY(proc.waitForStarted());
|
||||
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.
|
||||
QStringList gccArgs;
|
||||
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);
|
||||
QVERIFY(proc.waitForStarted());
|
||||
proc.write(mocOut);
|
||||
|
@ -436,6 +436,7 @@ private slots:
|
||||
void grabKeyboard();
|
||||
|
||||
void touchEventSynthesizedMouseEvent();
|
||||
void touchUpdateOnNewTouch();
|
||||
|
||||
void styleSheetPropagation();
|
||||
|
||||
@ -9757,6 +9758,9 @@ class TouchMouseWidget : public QWidget {
|
||||
public:
|
||||
explicit TouchMouseWidget(QWidget *parent = 0)
|
||||
: QWidget(parent),
|
||||
m_touchBeginCount(0),
|
||||
m_touchUpdateCount(0),
|
||||
m_touchEndCount(0),
|
||||
m_touchEventCount(0),
|
||||
m_acceptTouch(false),
|
||||
m_mouseEventCount(0),
|
||||
@ -9783,6 +9787,12 @@ protected:
|
||||
case QEvent::TouchBegin:
|
||||
case QEvent::TouchUpdate:
|
||||
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;
|
||||
if (m_acceptTouch)
|
||||
e->accept();
|
||||
@ -9807,6 +9817,9 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
int m_touchBeginCount;
|
||||
int m_touchUpdateCount;
|
||||
int m_touchEndCount;
|
||||
int m_touchEventCount;
|
||||
bool m_acceptTouch;
|
||||
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()
|
||||
{
|
||||
QTableView tw;
|
||||
|
2
tests/auto/widgets/widgets/qmenu/BLACKLIST
Normal file
@ -0,0 +1,2 @@
|
||||
[task258920_mouseBorder]
|
||||
osx
|
@ -2,3 +2,5 @@
|
||||
ubuntu-14.04
|
||||
[taskQTBUG4965_escapeEaten]
|
||||
ubuntu-14.04
|
||||
[task256322_highlight]
|
||||
osx
|
||||
|