From e5acaa12e3cb3f9eb41657eee8146d82fe436093 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 15 Feb 2020 20:23:40 +0100 Subject: QObject: treat T* -> bool conversions as narrowing Following wg21.link/LWG3228, it was found that a proper variant fix requires that T* -> bool conversions be treated as narrowing conversions in subclause wg21.link/dcl.init.lst. wg21.link/P1957R2 was accepted in Prague 2020 as a DR and retroactively applies to older C++ standards. Since we hard-code the algorithm of [dcl.init.lst], we can and must add this manually. [ChangeLog][QtCore][QObject] For the purposes of QT_NO_NARROWING_CONVERSIONS_IN_CONNECT, pointer (incl. pointer-to-member) to bool conversions are now considered narrowing. This matches the resolution of a defect report in C++ itself. Change-Id: Ifa9a3724c9c8ccd3dd6614928dbbe37477591dc1 Reviewed-by: Ville Voutilainen --- src/corelib/kernel/qobjectdefs_impl.h | 4 ++++ tests/auto/corelib/kernel/qobject/tst_qobject.cpp | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h index 31ecc8b20d..aed50d6c5a 100644 --- a/src/corelib/kernel/qobjectdefs_impl.h +++ b/src/corelib/kernel/qobjectdefs_impl.h @@ -285,11 +285,15 @@ namespace QtPrivate { { }; + template + using is_bool = std::is_same::type>; + template struct AreArgumentsNarrowedBase::type> : std::integral_constant::value && std::is_integral::value) || (std::is_floating_point::value && std::is_floating_point::value && sizeof(From) > sizeof(To)) || + ((std::is_pointer::value || std::is_member_pointer::value) && QtPrivate::is_bool::value) || ((std::is_integral::value || std::is_enum::value) && std::is_floating_point::value) || (std::is_integral::value && std::is_integral::value && (sizeof(From) > sizeof(To) diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 21615d6ec4..63d06497ce 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -7462,6 +7462,12 @@ void tst_QObject::checkArgumentsForNarrowing() FITS(bool, const QObject *&); FITS(int (*)(bool), void (QObject::*)()); + { + // wg21.link/P1957 + NARROWS(char*, bool); + NARROWS(void (QObject::*)(), bool); + } + #undef IS_UNSCOPED_ENUM_SIGNED #undef NARROWS_IF -- cgit v1.2.3 From 1fcb06f79aad556dc728b8aa1868156da8507c39 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 24 Feb 2020 10:32:42 +0100 Subject: Documentation: correctly use see-also tags to link to related members Change-Id: I764eb4730067cd704866191516dc4e8dd1820760 Reviewed-by: Nico Vertriest --- src/widgets/widgets/qdatetimeedit.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp index 64795d7ccb..0b9c15a157 100644 --- a/src/widgets/widgets/qdatetimeedit.cpp +++ b/src/widgets/widgets/qdatetimeedit.cpp @@ -669,7 +669,8 @@ void QDateTimeEdit::setTimeRange(const QTime &min, const QTime &max) \brief The currently displayed fields of the date time edit. Returns a bit set of the displayed sections for this format. - \a setDisplayFormat(), displayFormat() + + \sa setDisplayFormat(), displayFormat() */ QDateTimeEdit::Sections QDateTimeEdit::displayedSections() const @@ -682,7 +683,8 @@ QDateTimeEdit::Sections QDateTimeEdit::displayedSections() const \property QDateTimeEdit::currentSection \brief The current section of the spinbox. - \a setCurrentSection() + + \sa setCurrentSection() */ QDateTimeEdit::Section QDateTimeEdit::currentSection() const @@ -762,8 +764,7 @@ int QDateTimeEdit::sectionCount() const the cursorPosition is 5, currentSectionIndex returns 1. If the cursorPosition is 3, currentSectionIndex is 0, and so on. - \a setCurrentSection() - \sa currentSection() + \sa setCurrentSection(), currentSection() */ int QDateTimeEdit::currentSectionIndex() const -- cgit v1.2.3 From 8b9a02537300507d21d58ac7d3db4fe1a2f2fe62 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 24 Feb 2020 17:23:57 +0100 Subject: Make QDeadlineTimer test more resilient against VM starvation Flaky fails in this test suggest that the VM on which the test is executed does not get CPU resources allocated for enough time to make this test pass. This change makes the test more resilient by taking the measurements as quickly as possible. In addition, use a sanity-check based on std::chrono APIs to abort the test completely if we see that the clock has advanced too far to make the following tests meaningful. Change-Id: Ie6ac4ffb52f20e7774014f8222c9cd8f54d8a263 Fixes: QTBUG-64517 Reviewed-by: Friedemann Kleint --- .../kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp b/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp index 4e105d7dc7..35c5e7cb75 100644 --- a/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp +++ b/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp @@ -580,11 +580,26 @@ void tst_QDeadlineTimer::stdchrono() auto now = QDeadlineTimer::current(timerType); QTest::qSleep(minResolution); + auto sampling_start = steady_clock::now(); + auto steady_deadline = now.deadline(); + auto system_deadline = now.deadline(); auto steady_after = steady_clock::now(); auto system_after = system_clock::now(); + auto sampling_end = steady_clock::now(); + + auto sampling_diff = duration_cast(sampling_end - sampling_start).count(); + if (sampling_diff > minResolution/2) { + qWarning() << "Sampling clock took" << sampling_diff << "ms"; + QSKIP("Sampling clock took too long, aborting test", Abort); + } + auto total_diff = duration_cast(steady_after - steady_before).count(); + if (total_diff >= 3*minResolution) { + qWarning() << "Measurement took" << total_diff << "ms"; + QSKIP("Measurement took too long, aborting test", Abort); + } { - auto diff = duration_cast(steady_after - now.deadline()); + auto diff = duration_cast(steady_after - steady_deadline); QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); QDeadlineTimer dt_after(steady_after, timerType); @@ -592,7 +607,7 @@ void tst_QDeadlineTimer::stdchrono() ("now = " + QLocale().toString(now.deadlineNSecs()) + "; after = " + QLocale().toString(dt_after.deadlineNSecs())).toLatin1()); - diff = duration_cast(now.deadline() - steady_before); + diff = duration_cast(steady_deadline - steady_before); QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); QDeadlineTimer dt_before(steady_before, timerType); @@ -601,7 +616,7 @@ void tst_QDeadlineTimer::stdchrono() "; before = " + QLocale().toString(dt_before.deadlineNSecs())).toLatin1()); } { - auto diff = duration_cast(system_after - now.deadline()); + auto diff = duration_cast(system_after - system_deadline); QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); QDeadlineTimer dt_after(system_after, timerType); @@ -609,7 +624,7 @@ void tst_QDeadlineTimer::stdchrono() ("now = " + QLocale().toString(now.deadlineNSecs()) + "; after = " + QLocale().toString(dt_after.deadlineNSecs())).toLatin1()); - diff = duration_cast(now.deadline() - system_before); + diff = duration_cast(system_deadline - system_before); QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); QDeadlineTimer dt_before(system_before, timerType); -- cgit v1.2.3 From c6dd2e2367885d348e02440f23fd0bd54644c6f4 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 24 Feb 2020 14:00:49 +0100 Subject: Document the behavior of QLineEdit::inputMask correctly QLineEdit is unicode, and uses QChar::isLetter and QChar::isNumber to evaluate whether an input character is valid. There is no test for ASCII ranges, or converting of input characters to ASCII, so the documentation was wrong. [ChangeLog][QtWidgets][QLineEdit] the inputMask property has allowed any Letter or Number category character for the respective mask characters, not just ASCII. The documentation has been updated accordingly. Change-Id: Ied93cf6ddd334ac91bfbc275107a8eb83d231d80 Fixes: QTBUG-82291 Reviewed-by: Edward Welbourne Reviewed-by: Venugopal Shivashankar --- src/widgets/widgets/qlineedit.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index eaf31551d9..6aa641ebe6 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -1200,8 +1200,8 @@ QMargins QLineEdit::textMargins() const The input mask is an input template string. It can contain the following elements: \table - \row \li Mask Characters \li Defines the class of input characters that are - considered valid in this position + \row \li Mask Characters \li Defines the \l {QChar::} {Category} of input characters + that are considered valid in this position \row \li Meta Characters \li Various special meanings \row \li Separators \li All other characters are regarded as immutable separators \endtable @@ -1210,17 +1210,21 @@ QMargins QLineEdit::textMargins() const \table \header \li Mask Character \li Meaning - \row \li \c A \li ASCII alphabetic character required. A-Z, a-z. - \row \li \c a \li ASCII alphabetic character permitted but not required. - \row \li \c N \li ASCII alphanumeric character required. A-Z, a-z, 0-9. - \row \li \c n \li ASCII alphanumeric character permitted but not required. - \row \li \c X \li Any character required. - \row \li \c x \li Any character permitted but not required. - \row \li \c 9 \li ASCII digit required. 0-9. - \row \li \c 0 \li ASCII digit permitted but not required. - \row \li \c D \li ASCII digit required. 1-9. - \row \li \c d \li ASCII digit permitted but not required (1-9). - \row \li \c # \li ASCII digit or plus/minus sign permitted but not required. + \row \li \c A \li character of the Letter category required, such as A-Z, a-z. + \row \li \c a \li character of the Letter category permitted but not required. + \row \li \c N \li character of the Letter or Number category required, such as + A-Z, a-z, 0-9. + \row \li \c n \li character of the Letter or Number category permitted but not required. + \row \li \c X \li Any non-blank character required. + \row \li \c x \li Any non-blank character permitted but not required. + \row \li \c 9 \li character of the Number category required, e.g 0-9. + \row \li \c 0 \li character of the Number category permitted but not required. + \row \li \c D \li character of the Number category and larger than zero required, + such as 1-9 + \row \li \c d \li character of the Number category and larger than zero permitted but not + required, such as 1-9. + \row \li \c # \li character of the Number category, or plus/minus sign permitted but not + required. \row \li \c H \li Hexadecimal character required. A-F, a-f, 0-9. \row \li \c h \li Hexadecimal character permitted but not required. \row \li \c B \li Binary character required. 0-1. @@ -1262,7 +1266,7 @@ QMargins QLineEdit::textMargins() const To get range control (e.g., for an IP address) use masks together with \l{setValidator()}{validators}. - \sa maxLength + \sa maxLength, QChar::isLetter(), QChar::isNumber(), QChar::digitValue() */ QString QLineEdit::inputMask() const { -- cgit v1.2.3 From e8793476ac0d17dbadf9e05c3cf826c0f9d46710 Mon Sep 17 00:00:00 2001 From: Sze Howe Koh Date: Wed, 26 Feb 2020 22:13:28 +0800 Subject: Doc: List alternative ways to get the MySQL C Connector The C Connector does not appear to be offered as a component in the MySQL 8.0.19.0 installer. Task-number: QTBUG-82187 Change-Id: I4b1ef83cca68e7bf6dd032ba35c0784354d7fed3 Reviewed-by: Christian Ehrlicher --- src/sql/doc/src/sql-driver.qdoc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/sql/doc/src/sql-driver.qdoc b/src/sql/doc/src/sql-driver.qdoc index f6fc90a7e9..a5cf28e5a7 100644 --- a/src/sql/doc/src/sql-driver.qdoc +++ b/src/sql/doc/src/sql-driver.qdoc @@ -170,28 +170,31 @@ \section3 How to Build the QMYSQL Plugin on Windows - You need to get the MySQL installation files (e.g. - \l {https://dev.mysql.com/downloads/installer/}{mysql-installer-web-community-8.0.18.0.msi}). - Run the installer, - select custom installation and install the MySQL C Connector + Get the \l{https://dev.mysql.com/downloads/installer/}{MySQL installer} (e.g. + \e{mysql-installer-web-community-8.0.18.0.msi}). Run the installer, + select "Custom" installation, and install the MySQL C Connector which matches your Qt installation (x86 or x64). - After installation make sure that the needed files are there: + After installation check that the needed files are there: \list \li \c {/lib/libmysql.lib} \li \c {/lib/libmysql.dll} \li \c {/include/mysql.h} \endlist - Build the plugin as follows (here it is assumed that the MySQL - C Connector is installed in + \note As of MySQL 8.0.19, the C Connector is no longer offered as a standalone + installable component. Instead, you can get \c{mysql.h} and \c{libmysql.*} by + installing the full MySQL Server (x64 only) or the + \l{https://downloads.mariadb.org/connector-c/}{MariaDB C Connector}. + + Build the plugin as follows (here it is assumed that \c{} is \c{C:/Program Files/MySQL/MySQL Connector C 6.1}): \snippet code/doc_src_sql-driver.qdoc 5 If you are not using a Microsoft compiler, replace \c nmake with \c - mingw32-make in the line above. + mingw32-make above. - When you distribute your application, remember to include libmysql.dll + When you distribute your application, remember to include \e libmysql.dll in your installation package. It must be placed in the same folder as the application executable. \e libmysql.dll additionally needs the MSVC runtime libraries which can be installed with -- cgit v1.2.3 From 0efdf54a16d785598a2e310733a43e51d8a521b8 Mon Sep 17 00:00:00 2001 From: Alexandra Cherdantseva Date: Mon, 20 Jan 2020 17:10:26 +0300 Subject: wasm: fix texture leak when window is destroyed in a different context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reproduce: Show first window in first canvas; Show second window in second canvas; After screens are rendered destroy first window in first canvas Change-Id: Ifbeb4824c1fdedecf24d5d20e58613d15c066420 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/wasm/qwasmbackingstore.cpp | 27 +++++++++++++++++++----- src/plugins/platforms/wasm/qwasmcompositor.cpp | 7 ++++-- src/plugins/platforms/wasm/qwasmcompositor.h | 5 +++-- src/plugins/platforms/wasm/qwasmintegration.cpp | 5 +++++ src/plugins/platforms/wasm/qwasmintegration.h | 1 + 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.cpp b/src/plugins/platforms/wasm/qwasmbackingstore.cpp index 7e8a382512..6ac685083d 100644 --- a/src/plugins/platforms/wasm/qwasmbackingstore.cpp +++ b/src/plugins/platforms/wasm/qwasmbackingstore.cpp @@ -36,7 +36,7 @@ #include #include #include - +#include #include QT_BEGIN_NAMESPACE @@ -53,12 +53,29 @@ QWasmBackingStore::QWasmBackingStore(QWasmCompositor *compositor, QWindow *windo QWasmBackingStore::~QWasmBackingStore() { + auto window = this->window(); + QWasmIntegration::get()->removeBackingStore(window); + destroy(); + QWasmWindow *wasmWindow = static_cast(window->handle()); + if (wasmWindow) + wasmWindow->setBackingStore(nullptr); } void QWasmBackingStore::destroy() { - if (m_texture->isCreated()) - m_texture->destroy(); + if (m_texture->isCreated()) { + auto context = m_compositor->context(); + auto currentContext = QOpenGLContext::currentContext(); + if (!currentContext || !QOpenGLContext::areSharing(context, currentContext)) { + QOffscreenSurface offScreenSurface(m_compositor->screen()->screen()); + offScreenSurface.setFormat(context->format()); + offScreenSurface.create(); + context->makeCurrent(&offScreenSurface); + m_texture->destroy(); + } else { + m_texture->destroy(); + } + } } QPaintDevice *QWasmBackingStore::paintDevice() @@ -81,9 +98,9 @@ void QWasmBackingStore::updateTexture() if (m_dirty.isNull()) return; - if (m_recreateTexture && m_texture->isCreated()) { + if (m_recreateTexture) { m_recreateTexture = false; - m_texture->destroy(); + destroy(); } if (!m_texture->isCreated()) { diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp index e9c4559971..2f0b0414d9 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.cpp +++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp @@ -59,7 +59,6 @@ QWasmCompositedWindow::QWasmCompositedWindow() QWasmCompositor::QWasmCompositor(QWasmScreen *screen) :QObject(screen) - , m_frameBuffer(nullptr) , m_blitter(new QOpenGLTextureBlitter) , m_needComposit(false) , m_inFlush(false) @@ -71,7 +70,6 @@ QWasmCompositor::QWasmCompositor(QWasmScreen *screen) QWasmCompositor::~QWasmCompositor() { - delete m_frameBuffer; destroy(); } @@ -748,3 +746,8 @@ QWasmScreen *QWasmCompositor::screen() { return static_cast(parent()); } + +QOpenGLContext *QWasmCompositor::context() +{ + return m_context.data(); +} diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h index 98f4a79b27..422f990175 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.h +++ b/src/plugins/platforms/wasm/qwasmcompositor.h @@ -125,11 +125,13 @@ public: static QWasmTitleBarOptions makeTitleBarOptions(const QWasmWindow *window); static QRect titlebarRect(QWasmTitleBarOptions tb, QWasmCompositor::SubControls subcontrol); + QWasmScreen *screen(); + QOpenGLContext *context(); + private slots: void frame(); private: - QWasmScreen *screen(); void notifyTopWindowChanged(QWasmWindow *window); void drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window); void drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window); @@ -138,7 +140,6 @@ private: void drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window); void drwPanelButton(); - QImage *m_frameBuffer; QScopedPointer m_context; QScopedPointer m_blitter; diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 9934f5ac19..f8eaa39f76 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -193,6 +193,11 @@ QPlatformBackingStore *QWasmIntegration::createPlatformBackingStore(QWindow *win #endif } +void QWasmIntegration::removeBackingStore(QWindow* window) +{ + m_backingStores.remove(window); +} + #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QWasmIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index 2102f5c226..2eb64ed366 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -88,6 +88,7 @@ public: void resizeScreen(const QString &canvasId); void resizeAllScreens(); void updateDpi(); + void removeBackingStore(QWindow* window); private: mutable QWasmFontDatabase *m_fontDb; -- cgit v1.2.3 From d32a6793a43dc64dab3364fe3052bc464192ba90 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 16 Jan 2020 09:33:59 +0100 Subject: MinGW: Fix debug-and-release configuration Make sure that, if Qt was configured with -debug-and-release, winmain and user apps are generated by default in debug-and-release mode, too. This amends 9b4ec1393fde2af7deb39b9a2f98bcc93635603f . Change-Id: I0f169d63ca98c9bde41114225004a0844425db33 Reviewed-by: Joerg Bornemann --- mkspecs/common/g++-win32.conf | 2 +- mkspecs/features/qt_helper_lib.prf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mkspecs/common/g++-win32.conf b/mkspecs/common/g++-win32.conf index 6369436863..c3a1f3a373 100644 --- a/mkspecs/common/g++-win32.conf +++ b/mkspecs/common/g++-win32.conf @@ -17,7 +17,7 @@ include(g++-base.conf) MAKEFILE_GENERATOR = MINGW QMAKE_PLATFORM = win32 mingw -CONFIG += precompile_header +CONFIG += debug_and_release debug_and_release_target precompile_header DEFINES += UNICODE _UNICODE WIN32 MINGW_HAS_SECURE_API=1 QMAKE_COMPILER_DEFINES += __GNUC__ _WIN32 # can't add 'DEFINES += WIN64' and 'QMAKE_COMPILER_DEFINES += _WIN64' defines for diff --git a/mkspecs/features/qt_helper_lib.prf b/mkspecs/features/qt_helper_lib.prf index 216c24c7aa..8a9672e603 100644 --- a/mkspecs/features/qt_helper_lib.prf +++ b/mkspecs/features/qt_helper_lib.prf @@ -60,7 +60,7 @@ win32|CONFIG(static, static|shared) { "QMAKE_DEFINES_$${ucmodule} = $$val_escape(MODULE_DEFINES)" android { MODULE_PRI_CONT += "QMAKE_LIBS_$${ucmodule} =" - } else: debug_and_release { + } else: qtConfig(debug_and_release): { win32: \ MODULE_DEBUG_LIBS = $$DESTDIR/$$prefix$${TARGET}d.$$suffix else: darwin: \ -- cgit v1.2.3 From 25677ec4b2957f7fd56618781dec28cb139f9df7 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 25 Feb 2020 15:59:31 +0100 Subject: Fix bounding box of zero-width entities in QFontEngineFT Freetype can give us non empty bounds for zero-width characters, this change just makes us skip metrics of characters already found to not contribute to text advance. The coretext and windows font-engines already uses the already calculated advance. Change-Id: I82b3521a4fb92614be509be5982cd5ab9c1eb7de Fixes: QTBUG-58854 Reviewed-by: Konstantin Ritt Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qfontengine.cpp | 3 +++ .../fontdatabases/freetype/qfontengine_ft.cpp | 3 +++ .../gui/text/qfontmetrics/tst_qfontmetrics.cpp | 24 ++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 403a0510fa..2ed0f21d3e 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -663,6 +663,9 @@ glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout &glyphs) QFixed ymax = 0; QFixed xmax = 0; for (int i = 0; i < glyphs.numGlyphs; i++) { + // If shaping has found this should be ignored, ignore it. + if (!glyphs.advances[i] || glyphs.attributes[i].dontPrint) + continue; glyph_metrics_t bb = boundingBox(glyphs.glyphs[i]); QFixed x = overall.xoff + glyphs.offsets[i].x + bb.x; QFixed y = overall.yoff + glyphs.offsets[i].y + bb.y; diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp index 8c6cc8fbc1..d176f60d10 100644 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp +++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp @@ -1672,6 +1672,9 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs) QFixed ymax = 0; QFixed xmax = 0; for (int i = 0; i < glyphs.numGlyphs; i++) { + // If shaping has found this should be ignored, ignore it. + if (!glyphs.advances[i] || glyphs.attributes[i].dontPrint) + continue; Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0; if (!g) { if (!face) diff --git a/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp index a0e8525268..6fe3e20083 100644 --- a/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp +++ b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp @@ -59,6 +59,7 @@ private slots: void mnemonicTextWidth(); void leadingBelowLine(); void elidedMetrics(); + void zeroWidthMetrics(); }; void tst_QFontMetrics::same() @@ -358,5 +359,28 @@ void tst_QFontMetrics::elidedMetrics() QFontDatabase::removeApplicationFont(id); } +void tst_QFontMetrics::zeroWidthMetrics() +{ + QString zwnj(QChar(0x200c)); + QString zwsp(QChar(0x200b)); + + QFont font; + QFontMetricsF fm(font); + QCOMPARE(fm.horizontalAdvance(zwnj), 0); + QCOMPARE(fm.horizontalAdvance(zwsp), 0); + QCOMPARE(fm.boundingRect(zwnj).width(), 0); + QCOMPARE(fm.boundingRect(zwsp).width(), 0); + + QString string1 = QStringLiteral("(") + zwnj + QStringLiteral(")"); + QString string2 = QStringLiteral("(") + zwnj + zwnj + QStringLiteral(")"); + QString string3 = QStringLiteral("(") + zwsp + QStringLiteral(")"); + QString string4 = QStringLiteral("(") + zwsp + zwsp + QStringLiteral(")"); + + QCOMPARE(fm.horizontalAdvance(string1), fm.horizontalAdvance(string2)); + QCOMPARE(fm.horizontalAdvance(string3), fm.horizontalAdvance(string4)); + QCOMPARE(fm.boundingRect(string1).width(), fm.boundingRect(string2).width()); + QCOMPARE(fm.boundingRect(string3).width(), fm.boundingRect(string4).width()); +} + QTEST_MAIN(tst_QFontMetrics) #include "tst_qfontmetrics.moc" -- cgit v1.2.3 From e30aa59a897ca3849fb99c6393cfb426ed22d33b Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 14 Feb 2020 13:13:24 +0100 Subject: Fix a quadratic behavior in the BiDi algorithm Reset the lastETPosition after we changed DirET to DirEN, to avoid iterating over the same set of characters many times. Change-Id: Ib4113d0ba87ad70fc6bb386632eb094f943c080d Reviewed-by: Robert Loehning --- src/gui/text/qtextengine.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 209433dac5..cd056a743a 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -712,9 +712,8 @@ struct QBidiAlgorithm { analysis[pos].bidiDirection = QChar::DirEN; ++it; } - } else { - lastETPosition.clear(); } + lastETPosition.clear(); } last = current; lastPos = pos; -- cgit v1.2.3