Merge "Merge remote-tracking branch 'origin/release' into stable" into refs/staging/stable

This commit is contained in:
Frederik Gladhorn 2014-05-16 14:14:25 +02:00 committed by The Qt Project
commit 94f9c9678a
8 changed files with 185 additions and 35 deletions

View File

@ -34,8 +34,12 @@ QMAKE_DIR_REPLACE_SANE = PRECOMPILED_DIR OBJECTS_DIR MOC_DIR RCC_DIR UI_DIR
!build_pass:!isEmpty(_QMAKE_SUPER_CACHE_):force_independent { !build_pass:!isEmpty(_QMAKE_SUPER_CACHE_):force_independent {
# When doing a -prefix build of top-level qt5/qt.pro, we need to announce # When doing a -prefix build of top-level qt5/qt.pro, we need to announce
# this repo's module pris' location to the other repos. # this repo's output dir to the other repos.
isEmpty(MODULE_QMAKE_OUTDIR): MODULE_QMAKE_OUTDIR = $$shadowed($$dirname(_QMAKE_CONF_)) MODULE_BASE_OUTDIR = $$shadowed($$dirname(_QMAKE_CONF_))
!contains(QTREPOS, $$MODULE_BASE_OUTDIR): \
cache(QTREPOS, add super, MODULE_BASE_OUTDIR)
# This repo's module pris' location needs to be made known to qmake.
isEmpty(MODULE_QMAKE_OUTDIR): MODULE_QMAKE_OUTDIR = $$MODULE_BASE_OUTDIR
modpath = $$MODULE_QMAKE_OUTDIR/mkspecs/modules modpath = $$MODULE_QMAKE_OUTDIR/mkspecs/modules
!contains(QMAKEMODULES, $$modpath): \ !contains(QMAKEMODULES, $$modpath): \
cache(QMAKEMODULES, add super, modpath) cache(QMAKEMODULES, add super, modpath)

View File

@ -23,8 +23,9 @@ QDOC += -outputdir $$QMAKE_DOCS_OUTPUTDIR
!build_online_docs: \ !build_online_docs: \
QDOC += -installdir $$[QT_INSTALL_DOCS] QDOC += -installdir $$[QT_INSTALL_DOCS]
DOC_INDEXES = DOC_INDEXES =
for(qmod, QMAKEMODULES): \ for(qrep, QTREPOS): \
DOC_INDEXES += -indexdir $$section(qmod, /, 0, -3)/doc exists($$qrep/doc): \
DOC_INDEXES += -indexdir $$qrep/doc
qtver.name = QT_VERSION qtver.name = QT_VERSION
qtver.value = $$VERSION qtver.value = $$VERSION
isEmpty(qtver.value): qtver.value = $$MODULE_VERSION isEmpty(qtver.value): qtver.value = $$MODULE_VERSION

View File

@ -4,7 +4,6 @@
#define HAVE_OT #define HAVE_OT
#define HAVE_ATEXIT #define HAVE_ATEXIT
#define HB_NO_MT
#define HB_NO_UNICODE_FUNCS #define HB_NO_UNICODE_FUNCS
#define HB_DISABLE_DEPRECATED #define HB_DISABLE_DEPRECATED

View File

@ -237,7 +237,20 @@ QByteArray QUtf8::convertFromUnicode(const QChar *uc, int len, QTextCodec::Conve
QString QUtf8::convertToUnicode(const char *chars, int len) QString QUtf8::convertToUnicode(const char *chars, int len)
{ {
QString result(len + 1, Qt::Uninitialized); // worst case // UTF-8 to UTF-16 always needs the exact same number of words or less:
// UTF-8 UTF-16
// 1 byte 1 word
// 2 bytes 1 word
// 3 bytes 1 word
// 4 bytes 2 words (one surrogate pair)
// That is, we'll use the full buffer if the input is US-ASCII (1-byte UTF-8),
// half the buffer for U+0080-U+07FF text (e.g., Greek, Cyrillic, Arabic) or
// non-BMP text, and one third of the buffer for U+0800-U+FFFF text (e.g, CJK).
//
// The table holds for invalid sequences too: we'll insert one replacement char
// per invalid byte.
QString result(len, Qt::Uninitialized);
ushort *dst = reinterpret_cast<ushort *>(const_cast<QChar *>(result.constData())); ushort *dst = reinterpret_cast<ushort *>(const_cast<QChar *>(result.constData()));
const uchar *src = reinterpret_cast<const uchar *>(chars); const uchar *src = reinterpret_cast<const uchar *>(chars);
const uchar *end = src + len; const uchar *end = src + len;
@ -282,7 +295,18 @@ QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::Converte
int res; int res;
uchar ch = 0; uchar ch = 0;
QString result(need + len + 1, Qt::Uninitialized); // worst case // See above for buffer requirements for stateless decoding. However, that
// fails if the state is not empty. The following situations can add to the
// requirements:
// state contains chars starts with requirement
// 1 of 2 bytes valid continuation 0
// 2 of 3 bytes same 0
// 3 bytes of 4 same +1 (need to insert surrogate pair)
// 1 of 2 bytes invalid continuation +1 (need to insert replacement and restart)
// 2 of 3 bytes same +1 (same)
// 3 of 4 bytes same +1 (same)
QString result(need + len + 1, Qt::Uninitialized);
ushort *dst = reinterpret_cast<ushort *>(const_cast<QChar *>(result.constData())); ushort *dst = reinterpret_cast<ushort *>(const_cast<QChar *>(result.constData()));
const uchar *src = reinterpret_cast<const uchar *>(chars); const uchar *src = reinterpret_cast<const uchar *>(chars);
const uchar *end = src + len; const uchar *end = src + len;
@ -305,15 +329,17 @@ QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::Converte
const uchar *begin = &remainingCharsData[1]; const uchar *begin = &remainingCharsData[1];
res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(remainingCharsData[0], dst, begin, res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(remainingCharsData[0], dst, begin,
static_cast<const uchar *>(remainingCharsData) + remainingCharsCount + newCharsToCopy); static_cast<const uchar *>(remainingCharsData) + remainingCharsCount + newCharsToCopy);
if (res == QUtf8BaseTraits::EndOfString) { if (res == QUtf8BaseTraits::Error || (res == QUtf8BaseTraits::EndOfString && len == 0)) {
// special case for len == 0:
// if we were supplied an empty string, terminate the previous, unfinished sequence with error
++invalid;
*dst++ = replacement;
} else if (res == QUtf8BaseTraits::EndOfString) {
// if we got EndOfString again, then there were too few bytes in src; // if we got EndOfString again, then there were too few bytes in src;
// copy to our state and return // copy to our state and return
state->remainingChars = remainingCharsCount + newCharsToCopy; state->remainingChars = remainingCharsCount + newCharsToCopy;
memcpy(&state->state_data[0], remainingCharsData, state->remainingChars); memcpy(&state->state_data[0], remainingCharsData, state->remainingChars);
return QString(); return QString();
} else if (res == QUtf8BaseTraits::Error) {
++invalid;
*dst++ = replacement;
} else if (!headerdone && res >= 0) { } else if (!headerdone && res >= 0) {
// eat the UTF-8 BOM // eat the UTF-8 BOM
headerdone = true; headerdone = true;
@ -322,8 +348,10 @@ QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::Converte
} }
// adjust src now that we have maybe consumed a few chars // adjust src now that we have maybe consumed a few chars
//Q_ASSERT(res > remainingCharsCount) if (res >= 0) {
src += res - remainingCharsCount; Q_ASSERT(res > remainingCharsCount);
src += res - remainingCharsCount;
}
} }
} }

View File

@ -125,7 +125,7 @@ static uint crc32(const Char *ptr, size_t len, uint h)
# else # else
p += 4; p += 4;
for ( ; p <= e; p += 4) for ( ; p <= e; p += 4)
h = _mm_crc32_u32(h, *reinterpret_cast<const uint *>(p)); h = _mm_crc32_u32(h, *reinterpret_cast<const uint *>(p - 4));
p -= 4; p -= 4;
len = e - p; len = e - p;
# endif # endif

View File

@ -57,7 +57,7 @@
system: system:
\code \code
./configure -openssl-linked OPENSSL_LIBS='-L/opt/ssl/lib -lssl -lcrypto' OPENSSL_LIBS='-L/opt/ssl/lib -lssl -lcrypto' ./configure -openssl-linked
\endcode \endcode
To disable SSL support in a Qt build, configure Qt with the \c{-no-openssl} To disable SSL support in a Qt build, configure Qt with the \c{-no-openssl}

View File

@ -148,15 +148,17 @@ void QXcbConnection::initializeXInput2()
} }
case XIButtonClass: { case XIButtonClass: {
XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(devices[i].classes[c]); XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(devices[i].classes[c]);
for (int i=0; i < bci->num_buttons; ++i) { if (bci->num_buttons >= 5) {
const int buttonAtom = qatom(bci->labels[i]); Atom label4 = bci->labels[3];
if (buttonAtom == QXcbAtom::ButtonWheelUp Atom label5 = bci->labels[4];
|| buttonAtom == QXcbAtom::ButtonWheelDown) { if ((!label4 || qatom(label4) == QXcbAtom::ButtonWheelUp) && (!label5 || qatom(label5) == QXcbAtom::ButtonWheelDown))
scrollingDevice.legacyOrientations |= Qt::Vertical; scrollingDevice.legacyOrientations |= Qt::Vertical;
} else if (buttonAtom == QXcbAtom::ButtonHorizWheelLeft }
|| buttonAtom == QXcbAtom::ButtonHorizWheelRight) { if (bci->num_buttons >= 7) {
Atom label6 = bci->labels[5];
Atom label7 = bci->labels[6];
if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight))
scrollingDevice.legacyOrientations |= Qt::Horizontal; scrollingDevice.legacyOrientations |= Qt::Horizontal;
}
} }
break; break;
} }
@ -246,6 +248,7 @@ void QXcbConnection::xi2Select(xcb_window_t window)
} }
#endif // XCB_USE_XINPUT22 #endif // XCB_USE_XINPUT22
QSet<int> tabletDevices;
#ifndef QT_NO_TABLETEVENT #ifndef QT_NO_TABLETEVENT
// For each tablet, select some additional event types. // For each tablet, select some additional event types.
// Press, motion, etc. events must never be selected for _all_ devices // Press, motion, etc. events must never be selected for _all_ devices
@ -253,15 +256,19 @@ void QXcbConnection::xi2Select(xcb_window_t window)
// similar handlers useless and we have no intention to infect // similar handlers useless and we have no intention to infect
// all the pure xcb code with Xlib-based XI2. // all the pure xcb code with Xlib-based XI2.
if (!m_tabletData.isEmpty()) { if (!m_tabletData.isEmpty()) {
unsigned int tabletBitMask = bitMask;
unsigned char *xiTabletBitMask = reinterpret_cast<unsigned char *>(&tabletBitMask);
QVector<XIEventMask> xiEventMask(m_tabletData.count()); QVector<XIEventMask> xiEventMask(m_tabletData.count());
bitMask |= XI_ButtonPressMask; tabletBitMask |= XI_ButtonPressMask;
bitMask |= XI_ButtonReleaseMask; tabletBitMask |= XI_ButtonReleaseMask;
bitMask |= XI_MotionMask; tabletBitMask |= XI_MotionMask;
bitMask |= XI_PropertyEventMask; tabletBitMask |= XI_PropertyEventMask;
for (int i = 0; i < m_tabletData.count(); ++i) { for (int i = 0; i < m_tabletData.count(); ++i) {
xiEventMask[i].deviceid = m_tabletData.at(i).deviceId; int deviceId = m_tabletData.at(i).deviceId;
xiEventMask[i].mask_len = sizeof(bitMask); tabletDevices.insert(deviceId);
xiEventMask[i].mask = xiBitMask; xiEventMask[i].deviceid = deviceId;
xiEventMask[i].mask_len = sizeof(tabletBitMask);
xiEventMask[i].mask = xiTabletBitMask;
} }
XISelectEvents(xDisplay, window, xiEventMask.data(), m_tabletData.count()); XISelectEvents(xDisplay, window, xiEventMask.data(), m_tabletData.count());
} }
@ -271,17 +278,30 @@ void QXcbConnection::xi2Select(xcb_window_t window)
// Enable each scroll device // Enable each scroll device
if (!m_scrollingDevices.isEmpty()) { if (!m_scrollingDevices.isEmpty()) {
QVector<XIEventMask> xiEventMask(m_scrollingDevices.size()); QVector<XIEventMask> xiEventMask(m_scrollingDevices.size());
bitMask = XI_MotionMask; unsigned int scrollBitMask = 0;
unsigned char *xiScrollBitMask = reinterpret_cast<unsigned char *>(&scrollBitMask);
scrollBitMask = XI_MotionMask;
scrollBitMask |= XI_ButtonReleaseMask;
bitMask |= XI_MotionMask;
bitMask |= XI_ButtonReleaseMask; bitMask |= XI_ButtonReleaseMask;
int i=0; int i=0;
Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) { Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) {
if (tabletDevices.contains(scrollingDevice.deviceId))
continue; // All necessary events are already captured.
xiEventMask[i].deviceid = scrollingDevice.deviceId; xiEventMask[i].deviceid = scrollingDevice.deviceId;
xiEventMask[i].mask_len = sizeof(bitMask); if (m_touchDevices.contains(scrollingDevice.deviceId)) {
xiEventMask[i].mask = xiBitMask; xiEventMask[i].mask_len = sizeof(bitMask);
xiEventMask[i].mask = xiBitMask;
} else {
xiEventMask[i].mask_len = sizeof(scrollBitMask);
xiEventMask[i].mask = xiScrollBitMask;
}
i++; i++;
} }
XISelectEvents(xDisplay, window, xiEventMask.data(), m_scrollingDevices.size()); XISelectEvents(xDisplay, window, xiEventMask.data(), i);
} }
#else
Q_UNUSED(xiBitMask);
#endif #endif
} }
@ -655,13 +675,15 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData)
if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) { // ignore the physical buttons on the stylus if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) { // ignore the physical buttons on the stylus
tabletData->down = true; tabletData->down = true;
xi2ReportTabletEvent(*tabletData, xiEvent); xi2ReportTabletEvent(*tabletData, xiEvent);
} } else
handled = false;
break; break;
case XI_ButtonRelease: // stylus up case XI_ButtonRelease: // stylus up
if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) { if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) {
tabletData->down = false; tabletData->down = false;
xi2ReportTabletEvent(*tabletData, xiEvent); xi2ReportTabletEvent(*tabletData, xiEvent);
} } else
handled = false;
break; break;
case XI_Motion: case XI_Motion:
// Report TabletMove only when the stylus is touching the tablet. // Report TabletMove only when the stylus is touching the tablet.

View File

@ -80,6 +80,9 @@ private slots:
void utf8bom_data(); void utf8bom_data();
void utf8bom(); void utf8bom();
void utf8stateful_data();
void utf8stateful();
void utfHeaders_data(); void utfHeaders_data();
void utfHeaders(); void utfHeaders();
@ -1611,6 +1614,99 @@ void tst_QTextCodec::utf8bom()
QCOMPARE(codec->toUnicode(data.constData(), data.length(), &state), result); QCOMPARE(codec->toUnicode(data.constData(), data.length(), &state), result);
} }
void tst_QTextCodec::utf8stateful_data()
{
QTest::addColumn<QByteArray>("buffer1");
QTest::addColumn<QByteArray>("buffer2");
QTest::addColumn<QString>("result"); // null QString indicates decoder error
// valid buffer continuations
QTest::newRow("1of2+valid") << QByteArray("\xc2") << QByteArray("\xa0") << "\xc2\xa0";
QTest::newRow("1of3+valid") << QByteArray("\xe0") << QByteArray("\xa0\x80") << "\xe0\xa0\x80";
QTest::newRow("2of3+valid") << QByteArray("\xe0\xa0") << QByteArray("\x80") << "\xe0\xa0\x80";
QTest::newRow("1of4+valid") << QByteArray("\360") << QByteArray("\220\210\203") << "\360\220\210\203";
QTest::newRow("2of4+valid") << QByteArray("\360\220") << QByteArray("\210\203") << "\360\220\210\203";
QTest::newRow("3of4+valid") << QByteArray("\360\220\210") << QByteArray("\203") << "\360\220\210\203";
QTest::newRow("1ofBom+valid") << QByteArray("\xef") << QByteArray("\xbb\xbf") << "";
QTest::newRow("2ofBom+valid") << QByteArray("\xef\xbb") << QByteArray("\xbf") << "";
// invalid continuation
QTest::newRow("1of2+invalid") << QByteArray("\xc2") << QByteArray("a") << QString();
QTest::newRow("1of3+invalid") << QByteArray("\xe0") << QByteArray("a") << QString();
QTest::newRow("2of3+invalid") << QByteArray("\xe0\xa0") << QByteArray("a") << QString();
QTest::newRow("1of4+invalid") << QByteArray("\360") << QByteArray("a") << QString();
QTest::newRow("2of4+invalid") << QByteArray("\360\220") << QByteArray("a") << QString();
QTest::newRow("3of4+invalid") << QByteArray("\360\220\210") << QByteArray("a") << QString();
// invalid: sequence too short (the empty second buffer causes a state reset)
QTest::newRow("1of2+empty") << QByteArray("\xc2") << QByteArray() << QString();
QTest::newRow("1of3+empty") << QByteArray("\xe0") << QByteArray() << QString();
QTest::newRow("2of3+empty") << QByteArray("\xe0\xa0") << QByteArray() << QString();
QTest::newRow("1of4+empty") << QByteArray("\360") << QByteArray() << QString();
QTest::newRow("2of4+empty") << QByteArray("\360\220") << QByteArray() << QString();
QTest::newRow("3of4+empty") << QByteArray("\360\220\210") << QByteArray() << QString();
// overlong sequence:
QTest::newRow("overlong-1of2") << QByteArray("\xc1") << QByteArray("\x81") << QString();
QTest::newRow("overlong-1of3") << QByteArray("\xe0") << QByteArray("\x81\x81") << QString();
QTest::newRow("overlong-2of3") << QByteArray("\xe0\x81") << QByteArray("\x81") << QString();
QTest::newRow("overlong-1of4") << QByteArray("\xf0") << QByteArray("\x80\x81\x81") << QString();
QTest::newRow("overlong-2of4") << QByteArray("\xf0\x80") << QByteArray("\x81\x81") << QString();
QTest::newRow("overlong-3of4") << QByteArray("\xf0\x80\x81") << QByteArray("\x81") << QString();
// out of range:
// leading byte 0xF4 can produce codepoints above U+10FFFF, which aren't valid
QTest::newRow("outofrange1-1of4") << QByteArray("\xf4") << QByteArray("\x90\x80\x80") << QString();
QTest::newRow("outofrange1-2of4") << QByteArray("\xf4\x90") << QByteArray("\x80\x80") << QString();
QTest::newRow("outofrange1-3of4") << QByteArray("\xf4\x90\x80") << QByteArray("\x80") << QString();
QTest::newRow("outofrange2-1of4") << QByteArray("\xf5") << QByteArray("\x90\x80\x80") << QString();
QTest::newRow("outofrange2-2of4") << QByteArray("\xf5\x90") << QByteArray("\x80\x80") << QString();
QTest::newRow("outofrange2-3of4") << QByteArray("\xf5\x90\x80") << QByteArray("\x80") << QString();
QTest::newRow("outofrange-1of5") << QByteArray("\xf8") << QByteArray("\x88\x80\x80\x80") << QString();
QTest::newRow("outofrange-2of5") << QByteArray("\xf8\x88") << QByteArray("\x80\x80\x80") << QString();
QTest::newRow("outofrange-3of5") << QByteArray("\xf8\x88\x80") << QByteArray("\x80\x80") << QString();
QTest::newRow("outofrange-4of5") << QByteArray("\xf8\x88\x80\x80") << QByteArray("\x80") << QString();
QTest::newRow("outofrange-1of6") << QByteArray("\xfc") << QByteArray("\x84\x80\x80\x80\x80") << QString();
QTest::newRow("outofrange-2of6") << QByteArray("\xfc\x84") << QByteArray("\x80\x80\x80\x80") << QString();
QTest::newRow("outofrange-3of6") << QByteArray("\xfc\x84\x80") << QByteArray("\x80\x80\x80") << QString();
QTest::newRow("outofrange-4of6") << QByteArray("\xfc\x84\x80\x80") << QByteArray("\x80\x80") << QString();
QTest::newRow("outofrange-5of6") << QByteArray("\xfc\x84\x80\x80\x80") << QByteArray("\x80") << QString();
}
void tst_QTextCodec::utf8stateful()
{
QFETCH(QByteArray, buffer1);
QFETCH(QByteArray, buffer2);
QFETCH(QString, result);
QTextCodec *utf8codec = QTextCodec::codecForName("utf-8");
QVERIFY(utf8codec);
QTextCodec::ConverterState state;
memset(&state, 0, sizeof state);
QString decoded1 = utf8codec->toUnicode(buffer1, buffer1.size(), &state);
if (result.isNull()) {
// the decoder may have found an early error (invalidChars > 0):
// if it has, remainingChars == 0;
// if it hasn't, then it must have a state
QVERIFY2((state.remainingChars == 0) != (state.invalidChars == 0),
"remainingChars = " + QByteArray::number(state.remainingChars) +
"; invalidChars = " + QByteArray::number(state.invalidChars));
} else {
QVERIFY(state.remainingChars > 0);
QCOMPARE(state.invalidChars, 0);
}
QString decoded2 = utf8codec->toUnicode(buffer2, buffer2.size(), &state);
QCOMPARE(state.remainingChars, 0);
if (result.isNull()) {
QVERIFY(state.invalidChars > 0);
} else {
QCOMPARE(decoded1 + decoded2, result);
}
}
void tst_QTextCodec::utfHeaders_data() void tst_QTextCodec::utfHeaders_data()
{ {
QTest::addColumn<QByteArray>("codecName"); QTest::addColumn<QByteArray>("codecName");