diff options
author | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2015-05-04 13:05:26 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2015-05-04 13:05:40 +0200 |
commit | 98cf120f5e1803867ab8065778d8dec3f26ad2e4 (patch) | |
tree | 80e6ca98ab4415d88209a4f82890535e20a9805a | |
parent | 4db5d3ccd17d448b59db491e2f261892f31fec74 (diff) | |
parent | 1f281bfd63402b50f3db378a027da26ca52ffb27 (diff) |
Merge remote-tracking branch 'origin/5.4.2' into 5.4
Change-Id: I209def43673df62c75add4f623350fb1c98887a1
27 files changed, 408 insertions, 217 deletions
@@ -674,7 +674,7 @@ CFG_SSE4_1=auto CFG_SSE4_2=auto CFG_AVX=auto CFG_AVX2=auto -CFG_REDUCE_RELOCATIONS=auto +CFG_REDUCE_RELOCATIONS=no CFG_ACCESSIBILITY=auto CFG_ACCESSIBILITY_ATSPI_BRIDGE=no # will be enabled depending on dbus and accessibility being enabled CFG_NEON=auto diff --git a/dist/changes-5.4.2 b/dist/changes-5.4.2 new file mode 100644 index 0000000000..e1ad9b6846 --- /dev/null +++ b/dist/changes-5.4.2 @@ -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 diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index a8583cde17..79722183bf 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -1100,7 +1100,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); diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java index 75f10ad3ba..a790e0ef6f 100644 --- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java +++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java @@ -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 { diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp index 11510a8397..760ca3d933 100644 --- a/src/corelib/io/qnoncontiguousbytedevice.cpp +++ b/src/corelib/io/qnoncontiguousbytedevice.cpp @@ -236,6 +236,11 @@ qint64 QNonContiguousByteDeviceByteArrayImpl::size() return byteArray->size(); } +qint64 QNonContiguousByteDeviceByteArrayImpl::pos() +{ + return currentPosition; +} + QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb) : QNonContiguousByteDevice(), currentPosition(0) { @@ -273,6 +278,11 @@ bool QNonContiguousByteDeviceRingBufferImpl::atEnd() return currentPosition >= size(); } +qint64 QNonContiguousByteDeviceRingBufferImpl::pos() +{ + return currentPosition; +} + bool QNonContiguousByteDeviceRingBufferImpl::reset() { if (resetDisabled) @@ -406,6 +416,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; diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h index c05ae11b0f..4d7b7b043e 100644 --- a/src/corelib/io/qnoncontiguousbytedevice_p.h +++ b/src/corelib/io/qnoncontiguousbytedevice_p.h @@ -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; void disableReset(); bool isResetDisabled() { return resetDisabled; } @@ -106,6 +107,7 @@ public: bool atEnd(); bool reset(); qint64 size(); + qint64 pos() Q_DECL_OVERRIDE; protected: QByteArray* byteArray; qint64 currentPosition; @@ -121,6 +123,7 @@ public: bool atEnd(); bool reset(); qint64 size(); + qint64 pos() Q_DECL_OVERRIDE; protected: QSharedPointer<QRingBuffer> ringBuffer; qint64 currentPosition; @@ -138,6 +141,7 @@ public: bool atEnd(); bool reset(); qint64 size(); + qint64 pos() Q_DECL_OVERRIDE; protected: QIODevice* device; QByteArray* currentReadBuffer; diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 9cf9947b6c..14c8b4c0f4 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -726,7 +726,7 @@ public: }; QJpegHandlerPrivate(QJpegHandler *qq) - : quality(75), exifOrientation(1), iod_src(0), state(Ready), q(qq) + : quality(75), iod_src(0), state(Ready), q(qq) {} ~QJpegHandlerPrivate() @@ -741,10 +741,8 @@ public: bool readJpegHeader(QIODevice*); bool read(QImage *image); - void applyExifOrientation(QImage *image); int quality; - int exifOrientation; QVariant size; QImage::Format format; QSize scaledSize; @@ -762,97 +760,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 */ @@ -872,7 +779,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); @@ -884,8 +790,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; @@ -903,18 +807,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; } @@ -928,48 +823,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) @@ -981,7 +834,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; diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 9f63280bf8..49c6793b1f 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -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,13 +147,13 @@ 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); QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)), this, SLOT(_q_encryptedBytesWritten(qint64)), - Qt::DirectConnection); + Qt::QueuedConnection); if (ignoreAllSslErrors) sslSocket->ignoreSslErrors(); @@ -186,8 +190,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(); + } } @@ -353,6 +360,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; } @@ -659,6 +674,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(); @@ -734,7 +755,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, diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 692c0e6a94..231fe11135 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -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 diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp index 28e10f751e..3357948519 100644 --- a/src/network/access/qhttpprotocolhandler.cpp +++ b/src/network/access/qhttpprotocolhandler.cpp @@ -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 diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index 16610828cb..b553409391 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -187,6 +187,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(), @@ -194,7 +195,8 @@ public: m_amount(0), m_data(0), m_atEnd(aE), - m_size(s) + m_size(s), + m_pos(0) { } @@ -202,6 +204,11 @@ public: { } + qint64 pos() Q_DECL_OVERRIDE + { + return m_pos; + } + const char* readPointer(qint64 maximumLength, qint64 &len) { if (m_amount > 0) { @@ -229,11 +236,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; } @@ -250,10 +256,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; } @@ -264,8 +281,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; @@ -285,7 +307,7 @@ signals: // to main thread: void wantData(qint64); - void processedData(qint64); + void processedData(qint64 pos, qint64 amount); void resetData(bool *b); }; diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 4ce7303dbb..974a101e9c 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -424,6 +424,7 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate() , synchronous(false) , state(Idle) , statusCode(0) + , uploadByteDevicePosition(false) , uploadDeviceChoking(false) , outgoingData(0) , bytesUploaded(-1) @@ -863,9 +864,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); @@ -873,8 +874,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! @@ -1268,12 +1269,22 @@ void QNetworkReplyHttpImplPrivate::replySslConfigurationChanged(const QSslConfig 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, ""); + return; + } uploadByteDevice->advanceReadPointer(amount); + uploadByteDevicePosition += amount; } // Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread @@ -1298,7 +1309,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() diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index 77d9c5a368..1940922f6e 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -120,7 +120,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()) @@ -144,7 +144,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 @@ -195,6 +195,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; @@ -283,7 +284,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(); diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h index c3bd1fb504..be5d4b7b71 100644 --- a/src/widgets/itemviews/qabstractitemview_p.h +++ b/src/widgets/itemviews/qabstractitemview_p.h @@ -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); } diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg Binary files differdeleted file mode 100644 index aaa4ac4e10..0000000000 --- a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg +++ /dev/null diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg Binary files differdeleted file mode 100644 index a61d2723d7..0000000000 --- a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg +++ /dev/null diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg Binary files differdeleted file mode 100644 index 43e56dcef7..0000000000 --- a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg +++ /dev/null diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg Binary files differdeleted file mode 100644 index d5d06f7409..0000000000 --- a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg +++ /dev/null diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg Binary files differdeleted file mode 100644 index 1886f3775e..0000000000 --- a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg +++ /dev/null diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6.jpg Binary files differdeleted file mode 100644 index 5cec757354..0000000000 --- a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6.jpg +++ /dev/null diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6_motorola.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6_motorola.jpg Binary files differdeleted file mode 100644 index 0aa164b78b..0000000000 --- a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6_motorola.jpg +++ /dev/null diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg Binary files differdeleted file mode 100644 index b3dcc466a9..0000000000 --- a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg +++ /dev/null diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg Binary files differdeleted file mode 100644 index 8bc390e2b9..0000000000 --- a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg +++ /dev/null diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 309d3a80c5..33302edfeb 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -173,9 +173,6 @@ private slots: void invertPixelsRGB_data(); void invertPixelsRGB(); - void exifOrientation_data(); - void exifOrientation(); - void cleanupFunctions(); private: @@ -2649,36 +2646,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); diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 3ccedf6248..d2edf67a82 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -457,6 +457,10 @@ private Q_SLOTS: void putWithRateLimiting(); +#ifndef QT_NO_SSL + void putWithServerClosingConnectionImmediately(); +#endif + // NOTE: This test must be last! void parentingRepliesToTheApp(); private: @@ -4718,18 +4722,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"); @@ -4740,11 +4748,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 @@ -4753,6 +4762,7 @@ public slots: public: QSslSocket *socket; + bool m_ssl; }; // very similar to ioPostToHttpUploadProgress but for SSL @@ -4780,7 +4790,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 @@ -4788,7 +4798,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); @@ -7905,6 +7915,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() diff --git a/tests/auto/widgets/widgets/qmenu/BLACKLIST b/tests/auto/widgets/widgets/qmenu/BLACKLIST new file mode 100644 index 0000000000..de49d5ff45 --- /dev/null +++ b/tests/auto/widgets/widgets/qmenu/BLACKLIST @@ -0,0 +1,2 @@ +[task258920_mouseBorder] +osx diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 6e9d4aa80b..db0791b75c 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -1696,7 +1696,7 @@ void Configure::applySpecSpecifics() dictionary[ "LARGE_FILE" ] = "no"; dictionary[ "ANGLE" ] = "no"; dictionary[ "DYNAMICGL" ] = "no"; - dictionary[ "REDUCE_RELOCATIONS" ] = "yes"; + dictionary[ "REDUCE_RELOCATIONS" ] = "no"; dictionary[ "QT_GETIFADDRS" ] = "no"; dictionary[ "QT_XKBCOMMON" ] = "no"; dictionary["ANDROID_STYLE_ASSETS"] = "yes"; |