From eea978b9744c24200496af4f8a37d76228a29320 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Wed, 19 May 2010 16:33:48 +0200 Subject: Fixed an assert in QMenu The code was changed and changed the behaviour. This is basically a kind of revert. Reviewed-By: gabi Task-Number: QTBUG-10735 --- src/gui/widgets/qmenu.cpp | 12 +--------- tests/auto/qmenu/tst_qmenu.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index f84059d..7941c4e 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -983,19 +983,9 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e) return false; } -class ExceptionGuard -{ -public: - inline ExceptionGuard(bool *w = 0) : watched(w) { Q_ASSERT(!(*watched)); *watched = true; } - inline ~ExceptionGuard() { *watched = false; } - inline operator bool() { return *watched; } -private: - bool *watched; -}; - void QMenuPrivate::activateCausedStack(const QList > &causedStack, QAction *action, QAction::ActionEvent action_e, bool self) { - ExceptionGuard guard(&activationRecursionGuard); + QBoolBlocker guard(activationRecursionGuard); #ifdef QT3_SUPPORT const int actionId = q_func()->findIdForAction(action); #endif diff --git a/tests/auto/qmenu/tst_qmenu.cpp b/tests/auto/qmenu/tst_qmenu.cpp index e10d7ee..c8dc516 100644 --- a/tests/auto/qmenu/tst_qmenu.cpp +++ b/tests/auto/qmenu/tst_qmenu.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -106,6 +107,7 @@ private slots: void pushButtonPopulateOnAboutToShow(); void QTBUG7907_submenus_autoselect(); void QTBUG7411_submenus_activate(); + void QTBUG_10735_crashWithDialog(); protected slots: void onActivated(QAction*); void onHighlighted(QAction*); @@ -969,5 +971,57 @@ void tst_QMenu::QTBUG7411_submenus_activate() +class MyMenu : public QMenu +{ + Q_OBJECT +public: + MyMenu() : m_currentIndex(0) + { + for (int i = 0; i < 2; ++i) + dialogActions[i] = addAction( QString("dialog %1").arg(i), dialogs + i, SLOT(exec())); + } + + + void activateAction(int index) + { + m_currentIndex = index; + popup(QPoint()); + QTest::qWaitForWindowShown(this); + setActiveAction(dialogActions[index]); + QTimer::singleShot(0, this, SLOT(checkVisibility())); + QTest::keyClick(this, Qt::Key_Enter); //activation + } + +public slots: + void activateLastAction() + { + activateAction(1); + } + + void checkVisibility() + { + QTRY_VERIFY(dialogs[m_currentIndex].isVisible()); + if (m_currentIndex == 1) { + QApplication::closeAllWindows(); //this is the end of the test + } + } + + +private: + QAction *dialogActions[2]; + QDialog dialogs[2]; + int m_currentIndex; +}; + +void tst_QMenu::QTBUG_10735_crashWithDialog() +{ + MyMenu menu; + + QTimer::singleShot(1000, &menu, SLOT(activateLastAction())); + menu.activateAction(0); + +} + + QTEST_MAIN(tst_QMenu) #include "tst_qmenu.moc" -- cgit v0.12 From c98ccc13252aa625f552ae2f05f47e7e5f475aaa Mon Sep 17 00:00:00 2001 From: Ritt Konstantin Date: Thu, 20 May 2010 10:46:05 +0200 Subject: prefer QChar::*surrogate() over hardcoded values Merge-request: 2393 Reviewed-by: Olivier Goffart --- src/corelib/tools/qstring.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 612c492..9e80938 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -939,11 +939,11 @@ int QString::toWCharArray(wchar_t *array) const const unsigned short *uc = utf16(); for (int i = 0; i < length(); ++i) { uint u = uc[i]; - if (u >= 0xd800 && u < 0xdc00 && i < length()-1) { + if (QChar::isHighSurrogate(u) && i + 1 < length()) { ushort low = uc[i+1]; - if (low >= 0xdc00 && low < 0xe000) { + if (QChar::isLowSurrogate(low)) { + u = QChar::surrogateToUcs4(u, low); ++i; - u = (u - 0xd800)*0x400 + (low - 0xdc00) + 0x10000; } } *a = wchar_t(u); -- cgit v0.12 From 2a00c5582c23e5e7aee858725d27da4d725d03cf Mon Sep 17 00:00:00 2001 From: Ritt Konstantin Date: Thu, 20 May 2010 10:46:07 +0200 Subject: prevent fake normalization if normalization was requested for QChar::Unicode_Unassigned version; treat it like latest supported version instead Merge-request: 2393 Reviewed-by: Olivier Goffart --- src/corelib/tools/qstring.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 9e80938..6acbcec 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -6195,8 +6195,10 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar:: if (simple) return; - QString &s = *data; - if (version != UNICODE_DATA_VERSION) { + if (version == QChar::Unicode_Unassigned) { + version = UNICODE_DATA_VERSION; + } else if (version != UNICODE_DATA_VERSION) { + QString &s = *data; for (int i = 0; i < NumNormalizationCorrections; ++i) { const NormalizationCorrection &n = uc_normalization_corrections[i]; if (n.version > version) { -- cgit v0.12 From 8b3efa13709b24b5bc5d6356d8c8d94f06209fd5 Mon Sep 17 00:00:00 2001 From: Ritt Konstantin Date: Thu, 20 May 2010 10:46:09 +0200 Subject: use new QChar::requiresSurrogates() instead of hardcoded value this also fixes handling of codepoint 0x10000 ("ucs4 > 0x10000" s/>/>=/) Merge-request: 2393 Reviewed-by: Olivier Goffart --- src/corelib/tools/qchar.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index ddb1516..29ecf10 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -1480,9 +1480,9 @@ static void decomposeHelper(QString *str, bool canonical, QChar::UnicodeVersion if (!d || (canonical && tag != QChar::Canonical)) continue; - s.replace(uc - utf16, ucs4 > 0x10000 ? 2 : 1, (const QChar *)d, length); - // since the insert invalidates the pointers and we do decomposition recursive int pos = uc - utf16; + s.replace(pos, QChar::requiresSurrogates(ucs4) ? 2 : 1, reinterpret_cast(d), length); + // since the insert invalidates the pointers and we do decomposition recursive utf16 = reinterpret_cast(s.data()); uc = utf16 + pos + length; } @@ -1600,13 +1600,13 @@ static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, in QChar *uc = s.data(); int p = pos; // exchange characters - if (u2 < 0x10000) { + if (!QChar::requiresSurrogates(u2)) { uc[p++] = u2; } else { uc[p++] = QChar::highSurrogate(u2); uc[p++] = QChar::lowSurrogate(u2); } - if (u1 < 0x10000) { + if (!QChar::requiresSurrogates(u1)) { uc[p++] = u1; } else { uc[p++] = QChar::highSurrogate(u1); @@ -1618,7 +1618,7 @@ static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, in --pos; } else { ++pos; - if (u1 > 0x10000) + if (QChar::requiresSurrogates(u1)) ++pos; } } -- cgit v0.12 From 8e5ac76a2907a7a89b31ed562b5d086adaad5faf Mon Sep 17 00:00:00 2001 From: Ritt Konstantin Date: Thu, 20 May 2010 10:46:10 +0200 Subject: fix canonicalOrderHelper() for some corner case where string ends with sequence like HiS, LowS, NotS. in this case, if combiningClass(HiS, LowS) > combiningClass(NotS), then result will be invalid due to early exit on (p2 >= s.length()-1) Merge-request: 2393 Reviewed-by: Olivier Goffart --- src/corelib/tools/qchar.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index 29ecf10..c3e9f0e 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -1567,20 +1567,20 @@ static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, in int p2 = pos+1; uint u1 = s.at(pos).unicode(); if (QChar(u1).isHighSurrogate()) { - ushort low = s.at(pos+1).unicode(); + ushort low = s.at(p2).unicode(); if (QChar(low).isLowSurrogate()) { - p2++; u1 = QChar::surrogateToUcs4(u1, low); if (p2 >= l) break; + ++p2; } } uint u2 = s.at(p2).unicode(); - if (QChar(u2).isHighSurrogate() && p2 < l-1) { + if (QChar(u2).isHighSurrogate() && p2 < l) { ushort low = s.at(p2+1).unicode(); if (QChar(low).isLowSurrogate()) { - p2++; u2 = QChar::surrogateToUcs4(u2, low); + ++p2; } } -- cgit v0.12 From 173e2c1ba81b9a2665c040a9e86d085131e5042e Mon Sep 17 00:00:00 2001 From: Ritt Konstantin Date: Thu, 20 May 2010 10:46:12 +0200 Subject: nano optimization of canonicalOrderHelper() by inlining & merging QChar::combiningClass() and QChar::unicodeVersion() Merge-request: 2393 Reviewed-by: Olivier Goffart --- src/corelib/tools/qchar.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index c3e9f0e..ed0af4e 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -1584,17 +1584,23 @@ static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, in } } - int c2 = QChar::combiningClass(u2); - if (QChar::unicodeVersion(u2) > version) - c2 = 0; - + ushort c2 = 0; + { + const QUnicodeTables::Properties *p = qGetProp(u2); + if ((QChar::UnicodeVersion)p->unicodeVersion <= version) + c2 = p->combiningClass; + } if (c2 == 0) { pos = p2+1; continue; } - int c1 = QChar::combiningClass(u1); - if (QChar::unicodeVersion(u1) > version) - c1 = 0; + + ushort c1 = 0; + { + const QUnicodeTables::Properties *p = qGetProp(u1); + if ((QChar::UnicodeVersion)p->unicodeVersion <= version) + c1 = p->combiningClass; + } if (c1 > c2) { QChar *uc = s.data(); -- cgit v0.12 From 9c13272ddeea2408c83eb12a9f1fcceeb6a7589e Mon Sep 17 00:00:00 2001 From: Ritt Konstantin Date: Thu, 20 May 2010 10:47:19 +0200 Subject: more subtests for QChar Merge-request: 2392 Reviewed-by: Olivier Goffart --- tests/auto/qchar/tst_qchar.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/auto/qchar/tst_qchar.cpp b/tests/auto/qchar/tst_qchar.cpp index 5ca2255..9f70b8c 100644 --- a/tests/auto/qchar/tst_qchar.cpp +++ b/tests/auto/qchar/tst_qchar.cpp @@ -75,6 +75,7 @@ private slots: void isPrint(); void isUpper(); void isLower(); + void isTitle(); void category(); void direction(); void joining(); @@ -234,6 +235,11 @@ void tst_QChar::isUpper() QVERIFY(!QChar('?').isUpper()); QVERIFY(QChar(0xC2).isUpper()); // A with ^ QVERIFY(!QChar(0xE2).isUpper()); // a with ^ + + for (uint codepoint = 0; codepoint <= UNICODE_LAST_CODEPOINT; ++codepoint) { + if (QChar::category(codepoint) == QChar::Letter_Uppercase) + QVERIFY(codepoint == QChar::toUpper(codepoint)); + } } void tst_QChar::isLower() @@ -245,6 +251,19 @@ void tst_QChar::isLower() QVERIFY(!QChar('?').isLower()); QVERIFY(!QChar(0xC2).isLower()); // A with ^ QVERIFY(QChar(0xE2).isLower()); // a with ^ + + for (uint codepoint = 0; codepoint <= UNICODE_LAST_CODEPOINT; ++codepoint) { + if (QChar::category(codepoint) == QChar::Letter_Lowercase) + QVERIFY(codepoint == QChar::toLower(codepoint)); + } +} + +void tst_QChar::isTitle() +{ + for (uint codepoint = 0; codepoint <= UNICODE_LAST_CODEPOINT; ++codepoint) { + if (QChar::category(codepoint) == QChar::Letter_Titlecase) + QVERIFY(codepoint == QChar::toTitleCase(codepoint)); + } } void tst_QChar::category() -- cgit v0.12 From 89a5f382e1eff75c3d3f015b3fce0a58b8079e04 Mon Sep 17 00:00:00 2001 From: Ritt Konstantin Date: Thu, 20 May 2010 10:47:21 +0200 Subject: improve Unicode Normalization autotest Merge-request: 2392 Reviewed-by: Olivier Goffart --- tests/auto/qchar/tst_qchar.cpp | 85 ++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/tests/auto/qchar/tst_qchar.cpp b/tests/auto/qchar/tst_qchar.cpp index 9f70b8c..93aaf96 100644 --- a/tests/auto/qchar/tst_qchar.cpp +++ b/tests/auto/qchar/tst_qchar.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #if defined(Q_OS_WINCE) #include @@ -84,7 +85,9 @@ private slots: void decomposition(); // void ligature(); void lineBreakClass(); + void normalization_data(); void normalization(); + void normalization_manual(); void normalizationCorrections(); void unicodeVersion(); #if defined(Q_OS_WINCE) @@ -505,31 +508,13 @@ void tst_QChar::lineBreakClass() QVERIFY(QUnicodeTables::lineBreakClass(0x0fffdu) == QUnicodeTables::LineBreak_AL); } -void tst_QChar::normalization() +void tst_QChar::normalization_data() { - { - QString composed; - composed += QChar(0xc0); - QString decomposed; - decomposed += QChar(0x41); - decomposed += QChar(0x300); + QTest::addColumn("columns"); + QTest::addColumn("part"); - QVERIFY(composed.normalized(QString::NormalizationForm_D) == decomposed); - QVERIFY(composed.normalized(QString::NormalizationForm_C) == composed); - QVERIFY(composed.normalized(QString::NormalizationForm_KD) == decomposed); - QVERIFY(composed.normalized(QString::NormalizationForm_KC) == composed); - } - { - QString composed; - composed += QChar(0xa0); - QString decomposed; - decomposed += QChar(0x20); - - QVERIFY(composed.normalized(QString::NormalizationForm_D) == composed); - QVERIFY(composed.normalized(QString::NormalizationForm_C) == composed); - QVERIFY(composed.normalized(QString::NormalizationForm_KD) == decomposed); - QVERIFY(composed.normalized(QString::NormalizationForm_KC) == decomposed); - } + int linenum = 0; + int part = 0; QFile f(SRCDIR "NormalizationTest.txt"); QVERIFY(f.exists()); @@ -537,6 +522,8 @@ void tst_QChar::normalization() f.open(QIODevice::ReadOnly); while (!f.atEnd()) { + linenum++; + QByteArray line; line.resize(1024); int len = f.readLine(line.data(), 1024); @@ -546,8 +533,11 @@ void tst_QChar::normalization() if (comment >= 0) line = line.left(comment); - if (line.startsWith("@")) + if (line.startsWith("@")) { + if (line.startsWith("@Part") && line.size() > 5 && QChar(line.at(5)).isDigit()) + part = QChar(line.at(5)).digitValue(); continue; + } if (line.isEmpty()) continue; @@ -560,8 +550,10 @@ void tst_QChar::normalization() Q_ASSERT(l.size() == 5); - QString columns[5]; + QStringList columns; for (int i = 0; i < 5; ++i) { + columns.append(QString()); + QList c = l.at(i).split(' '); Q_ASSERT(!c.isEmpty()); @@ -572,15 +564,26 @@ void tst_QChar::normalization() columns[i].append(QChar(uc)); else { // convert to utf16 - uc -= 0x10000; - ushort high = uc/0x400 + 0xd800; - ushort low = uc%0x400 + 0xdc00; + ushort high = QChar::highSurrogate(uc); + ushort low = QChar::lowSurrogate(uc); columns[i].append(QChar(high)); columns[i].append(QChar(low)); } } } + QString nm = QString("line #%1:").arg(linenum); + QTest::newRow(nm.toLatin1()) << columns << part; + } +} + +void tst_QChar::normalization() +{ + QFETCH(QStringList, columns); + QFETCH(int, part); + + Q_UNUSED(part) + // CONFORMANCE: // 1. The following invariants must be true for all conformant implementations // @@ -630,6 +633,32 @@ void tst_QChar::normalization() // ################# +} + +void tst_QChar::normalization_manual() +{ + { + QString composed; + composed += QChar(0xc0); + QString decomposed; + decomposed += QChar(0x41); + decomposed += QChar(0x300); + + QVERIFY(composed.normalized(QString::NormalizationForm_D) == decomposed); + QVERIFY(composed.normalized(QString::NormalizationForm_C) == composed); + QVERIFY(composed.normalized(QString::NormalizationForm_KD) == decomposed); + QVERIFY(composed.normalized(QString::NormalizationForm_KC) == composed); + } + { + QString composed; + composed += QChar(0xa0); + QString decomposed; + decomposed += QChar(0x20); + + QVERIFY(composed.normalized(QString::NormalizationForm_D) == composed); + QVERIFY(composed.normalized(QString::NormalizationForm_C) == composed); + QVERIFY(composed.normalized(QString::NormalizationForm_KD) == decomposed); + QVERIFY(composed.normalized(QString::NormalizationForm_KC) == decomposed); } } -- cgit v0.12