From 20e9422e069a27b7e29b54207447e6ca02b3a55a Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 23 May 2019 10:58:30 +0200 Subject: Do not ignore exit codes of install commands All calls to QINSTALL or QINSTALL_PROGRAM were written into Makefiles with a preceding dash which lets make ignore the command's exit code. Scripts (and users) calling 'make install' had no way to determine if an installation completely succeeded, unless they inspected make's output or the installation tree. Remove the leading dash from those commands to stop 'make install' on failure. Users who really want to ignore the exit codes can run 'make -k install'. [ChangeLog][qmake] Installation targets do not ignore the exit code of QINSTALL and QINSTALL_PROGRAM anymore. Fixes: QTBUG-18870 Change-Id: I7c072c896e6bd2b2ddba4b9c082c5bf627c90f50 Reviewed-by: Lars Knoll Reviewed-by: Simon Hausmann --- qmake/generators/makefile.cpp | 10 +++++----- qmake/generators/unix/unixmake.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index bf8eb3f5da..95452e507c 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -1294,9 +1294,9 @@ MakefileGenerator::writeInstalls(QTextStream &t, bool noBuild) dst_file += fi.fileName(); QString cmd; if (is_target || (!fi.isDir() && fi.isExecutable())) - cmd = QLatin1String("-$(QINSTALL_PROGRAM)"); + cmd = QLatin1String("$(QINSTALL_PROGRAM)"); else - cmd = QLatin1String("-$(QINSTALL)"); + cmd = QLatin1String("$(QINSTALL)"); cmd += " " + escapeFilePath(wild) + " " + escapeFilePath(dst_file); inst << cmd; if (!noStrip && !project->isActiveConfig("debug_info") && !project->isActiveConfig("nostrip") && @@ -1316,9 +1316,9 @@ MakefileGenerator::writeInstalls(QTextStream &t, bool noBuild) dst_file += filestr; QString cmd; if (installConfigValues.contains("executable")) - cmd = QLatin1String("-$(QINSTALL_PROGRAM)"); + cmd = QLatin1String("$(QINSTALL_PROGRAM)"); else - cmd = QLatin1String("-$(QINSTALL)"); + cmd = QLatin1String("$(QINSTALL)"); cmd += " " + escapeFilePath(wild) + " " + escapeFilePath(dst_file); inst << cmd; uninst.append(rm_dir_contents + " " + escapeFilePath(filePrefixRoot(root, fileFixify(dst_dir + filestr, FileFixifyAbsolute, false)))); @@ -1331,7 +1331,7 @@ MakefileGenerator::writeInstalls(QTextStream &t, bool noBuild) if (!dst_file.endsWith(Option::dir_sep)) dst_file += Option::dir_sep; dst_file += fi.fileName(); - QString cmd = QLatin1String("-$(QINSTALL) ") + + QString cmd = QLatin1String("$(QINSTALL) ") + escapeFilePath(dirstr + file) + " " + escapeFilePath(dst_file); inst << cmd; if (!noStrip && !project->isActiveConfig("debug_info") && !project->isActiveConfig("nostrip") && diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index 836737e77d..dbcf2a9a77 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -604,7 +604,7 @@ UnixMakefileGenerator::defaultInstall(const QString &t) dst = escapeFilePath(filePrefixRoot(root, targetdir + src.section('/', -1))); if(!ret.isEmpty()) ret += "\n\t"; - ret += "-$(QINSTALL) " + escapeFilePath(Option::fixPathToTargetOS(src, false)) + ' ' + dst; + ret += "$(QINSTALL) " + escapeFilePath(Option::fixPathToTargetOS(src, false)) + ' ' + dst; if(!uninst.isEmpty()) uninst.append("\n\t"); uninst.append("-$(DEL_FILE) " + dst); @@ -640,16 +640,16 @@ UnixMakefileGenerator::defaultInstall(const QString &t) QString copy_cmd; if (bundle == SolidBundle) { - copy_cmd += "-$(QINSTALL) " + src_targ + ' ' + plain_targ; + copy_cmd += "$(QINSTALL) " + src_targ + ' ' + plain_targ; } else if (project->first("TEMPLATE") == "lib" && project->isActiveConfig("staticlib")) { - copy_cmd += "-$(QINSTALL) " + src_targ + ' ' + dst_targ; + copy_cmd += "$(QINSTALL) " + src_targ + ' ' + dst_targ; } else if (!isAux) { if (bundle == SlicedBundle) { if (!ret.isEmpty()) ret += "\n\t"; ret += mkdir_p_asstring("\"`dirname " + dst_targ + "`\"", false); } - copy_cmd += "-$(QINSTALL_PROGRAM) " + src_targ + ' ' + dst_targ; + copy_cmd += "$(QINSTALL_PROGRAM) " + src_targ + ' ' + dst_targ; } if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") && project->values(ProKey(t + ".CONFIG")).indexOf("fix_rpath") != -1) { @@ -702,7 +702,7 @@ UnixMakefileGenerator::defaultInstall(const QString &t) ret += "\n\t"; ret += mkdir_p_asstring("\"`dirname " + dst + "`\"", false) + "\n\t"; ret += "-$(DEL_FILE) " + dst + "\n\t"; // Can't overwrite symlinks to directories - ret += "-$(QINSTALL) " + escapeFilePath(src) + " " + dst; + ret += "$(QINSTALL) " + escapeFilePath(src) + " " + dst; if (!uninst.isEmpty()) uninst.append("\n\t"); uninst.append("-$(DEL_FILE) " + dst); -- cgit v1.2.3 From 87748cc18e6a0d9e65933aa2462dc78ab8f9f22e Mon Sep 17 00:00:00 2001 From: Nils Jeisecke Date: Fri, 5 Jun 2015 17:48:00 +0200 Subject: QTextDocumentLayout: Avoid table border drawing artifacts As borders are always painted for single cells any rounding errors that occur when mapping from fixed point numbers to integers during raster painting will cause ugly drawing artifacts like extra pixels between cells or borders that overlap. To avoid this the following values are being rounded: - table offset - column positions and widths - row positions and cell heights For the column positions and widths the distribution constraints (total table width) are respected. Task-number: QTBUG-43589 Change-Id: I6308c113f8f9be3db8e9267629f26b5d65d2d7c7 Reviewed-by: Shawn Rutledge --- src/gui/text/qtextdocumentlayout.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index 7873faf2cb..e5cfa7f46e 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -931,7 +931,10 @@ void QTextDocumentLayoutPrivate::drawFrame(const QPointF &offset, QPainter *pain Q_ASSERT(!fd->sizeDirty); Q_ASSERT(!fd->layoutDirty); - const QPointF off = offset + fd->position.toPointF(); + // floor the offset to avoid painting artefacts when drawing adjacent borders + // we later also round table cell heights and widths + const QPointF off = QPointF(QPointF(offset + fd->position.toPointF()).toPoint()); + if (context.clip.isValid() && (off.y() > context.clip.bottom() || off.y() + fd->size.height.toReal() < context.clip.top() || off.x() > context.clip.right() || off.x() + fd->size.width.toReal() < context.clip.left())) @@ -1681,7 +1684,8 @@ recalc_minmax_widths: for (int n = 0; n < cspan; ++n) { const int col = i + n; QFixed w = widthToDistribute / (cspan - n); - td->minWidths[col] = qMax(td->minWidths.at(col), w); + // ceil to avoid going below minWidth when rounding all column widths later + td->minWidths[col] = qMax(td->minWidths.at(col), w).ceil(); widthToDistribute -= td->minWidths.at(col); if (widthToDistribute <= 0) break; @@ -1787,6 +1791,18 @@ recalc_minmax_widths: } } + // in order to get a correct border rendering we must ensure that the distance between + // two cells is exactly 2 * td->border pixel. we do this by rounding the calculated width + // values here. + // to minimize the total rounding error we propagate the rounding error for each width + // to its successor. + QFixed error = 0; + for (int i = 0; i < columns; ++i) { + QFixed orig = td->widths[i]; + td->widths[i] = (td->widths[i] - error).round(); + error = td->widths[i] - orig; + } + td->columnPositions.resize(columns); td->columnPositions[0] = leftMargin /*includes table border*/ + cellSpacing + td->border; @@ -1887,7 +1903,7 @@ relayout: if (cellRow != r) { // the last row gets all the remaining space if (cellRow + rspan - 1 == r) - td->heights[r] = qMax(td->heights.at(r), heightToDistribute.at(c) - dropDistance); + td->heights[r] = qMax(td->heights.at(r), heightToDistribute.at(c) - dropDistance).round(); continue; } } @@ -1908,7 +1924,7 @@ relayout: td, absoluteTableY, /*withPageBreaks =*/true); - const QFixed height = layoutStruct.y + bottomPadding + topPadding; + const QFixed height = (layoutStruct.y + bottomPadding + topPadding).round(); if (rspan > 1) heightToDistribute[c] = height + dropDistance; -- cgit v1.2.3 From 1798d3ddc80b05cf41ee61807ec433d624b6ed6b Mon Sep 17 00:00:00 2001 From: Mikhail Svetkin Date: Tue, 20 Mar 2018 14:25:56 +0100 Subject: rtems: Add Q_OS_RTEMS macro to detect RTEMS OS Change-Id: I45530cb7438a8f3ae8eac2e4be3c7d4472d9eec2 Reviewed-by: Thiago Macieira --- src/corelib/global/qsystemdetection.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h index a2e51fa330..02e2f77c6b 100644 --- a/src/corelib/global/qsystemdetection.h +++ b/src/corelib/global/qsystemdetection.h @@ -166,6 +166,8 @@ # define Q_OS_QNX #elif defined(__INTEGRITY) # define Q_OS_INTEGRITY +#elif defined(__rtems__) +# define Q_OS_RTEMS #elif defined(VXWORKS) /* there is no "real" VxWorks define - this has to be set in the mkspec! */ # define Q_OS_VXWORKS #elif defined(__HAIKU__) -- cgit v1.2.3 From a8162e1f59f2823bffddb0ee660829561b9b5090 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Wed, 22 May 2019 15:27:03 +0900 Subject: Replace QTESTLIB_USE_VALGRIND with a new feature 'valgrind' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I851788cb1872eef86c75c7bdb2de361a0ff2af6c Reviewed-by: Jörg Bornemann --- src/testlib/configure.json | 6 ++++++ src/testlib/qbenchmark.cpp | 2 +- src/testlib/qbenchmark_p.h | 8 +------- src/testlib/qbenchmarkvalgrind.cpp | 4 ---- src/testlib/qbenchmarkvalgrind_p.h | 2 ++ src/testlib/qtestcase.cpp | 12 ++++++------ src/testlib/testlib.pro | 9 +++++++-- 7 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/testlib/configure.json b/src/testlib/configure.json index df6132cdc2..726f614ee5 100644 --- a/src/testlib/configure.json +++ b/src/testlib/configure.json @@ -16,6 +16,12 @@ "purpose": "Provides a utility to test item models.", "condition": "features.itemmodel", "output": [ "publicFeature" ] + }, + "valgrind": { + "label": "Valgrind", + "purpose": "Profiling support with callgrind.", + "condition": "(config.linux || config.darwin) && features.process && features.regularexpression", + "output": [ "publicFeature" ] } }, diff --git a/src/testlib/qbenchmark.cpp b/src/testlib/qbenchmark.cpp index d49d07bb70..8d5543a0fc 100644 --- a/src/testlib/qbenchmark.cpp +++ b/src/testlib/qbenchmark.cpp @@ -82,7 +82,7 @@ QBenchmarkMeasurerBase * QBenchmarkGlobalData::createMeasurer() { QBenchmarkMeasurerBase *measurer = 0; if (0) { -#ifdef QTESTLIB_USE_VALGRIND +#if QT_CONFIG(valgrind) } else if (mode_ == CallgrindChildProcess || mode_ == CallgrindParentProcess) { measurer = new QBenchmarkCallgrindMeasurer; #endif diff --git a/src/testlib/qbenchmark_p.h b/src/testlib/qbenchmark_p.h index 3fa9c5f534..49868ac23a 100644 --- a/src/testlib/qbenchmark_p.h +++ b/src/testlib/qbenchmark_p.h @@ -55,12 +55,6 @@ #include -#if (defined(Q_OS_LINUX) || defined Q_OS_MACOS) && QT_CONFIG(process) -#define QTESTLIB_USE_VALGRIND -#else -#undef QTESTLIB_USE_VALGRIND -#endif - #if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE) && !defined(Q_OS_ANDROID) #define QTESTLIB_USE_PERF_EVENTS #else @@ -70,7 +64,7 @@ #include #include #include -#ifdef QTESTLIB_USE_VALGRIND +#if QT_CONFIG(valgrind) #include #endif #ifdef QTESTLIB_USE_PERF_EVENTS diff --git a/src/testlib/qbenchmarkvalgrind.cpp b/src/testlib/qbenchmarkvalgrind.cpp index 7d24eb8293..0dac804338 100644 --- a/src/testlib/qbenchmarkvalgrind.cpp +++ b/src/testlib/qbenchmarkvalgrind.cpp @@ -39,8 +39,6 @@ #include -#ifdef QTESTLIB_USE_VALGRIND - #include #include #include @@ -243,5 +241,3 @@ QTest::QBenchmarkMetric QBenchmarkCallgrindMeasurer::metricType() } QT_END_NAMESPACE - -#endif // QTESTLIB_USE_VALGRIND diff --git a/src/testlib/qbenchmarkvalgrind_p.h b/src/testlib/qbenchmarkvalgrind_p.h index 69219b9a65..0619be9f22 100644 --- a/src/testlib/qbenchmarkvalgrind_p.h +++ b/src/testlib/qbenchmarkvalgrind_p.h @@ -58,6 +58,8 @@ class QStringList; +QT_REQUIRE_CONFIG(valgrind); + QT_BEGIN_NAMESPACE class QBenchmarkValgrindUtils diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index cad29b5326..5faafba38d 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -574,7 +574,7 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool " -nocrashhandler : Disables the crash handler. Useful for debugging crashes.\n" "\n" " Benchmarking options:\n" -#ifdef QTESTLIB_USE_VALGRIND +#if QT_CONFIG(valgrind) " -callgrind : Use callgrind to time benchmarks\n" #endif #ifdef QTESTLIB_USE_PERF_EVENTS @@ -717,7 +717,7 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool } } else if (strcmp(argv[i], "-nocrashhandler") == 0) { QTest::noCrashHandler = true; -#ifdef QTESTLIB_USE_VALGRIND +#if QT_CONFIG(valgrind) } else if (strcmp(argv[i], "-callgrind") == 0) { if (QBenchmarkValgrindUtils::haveValgrind()) if (QFileInfo(QDir::currentPath()).isWritable()) { @@ -1459,7 +1459,7 @@ void TestMethods::invokeTests(QObject *testObject) const QScopedPointer watchDog; if (!debuggerPresent() -#ifdef QTESTLIB_USE_VALGRIND +#if QT_CONFIG(valgrind) && QBenchmarkGlobalData::current->mode() != QBenchmarkGlobalData::CallgrindChildProcess #endif ) { @@ -1866,7 +1866,7 @@ int QTest::qRun() { QTEST_ASSERT(currentTestObject); -#ifdef QTESTLIB_USE_VALGRIND +#if QT_CONFIG(valgrind) int callgrindChildExitCode = 0; #endif @@ -1886,7 +1886,7 @@ int QTest::qRun() } // !noCrashHandler #endif // Q_OS_WIN -#ifdef QTESTLIB_USE_VALGRIND +#if QT_CONFIG(valgrind) if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess) { if (Q_UNLIKELY(!qApp)) qFatal("QtTest: -callgrind option is not available with QTEST_APPLESS_MAIN"); @@ -1944,7 +1944,7 @@ int QTest::qRun() } #endif -#ifdef QTESTLIB_USE_VALGRIND +#if QT_CONFIG(valgrind) if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess) return callgrindChildExitCode; #endif diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro index f52a913a08..530bc6b425 100644 --- a/src/testlib/testlib.pro +++ b/src/testlib/testlib.pro @@ -17,7 +17,6 @@ HEADERS = \ qbenchmark_p.h \ qbenchmarkmeasurement_p.h \ qbenchmarktimemeasurers_p.h \ - qbenchmarkvalgrind_p.h \ qbenchmarkevent_p.h \ qbenchmarkperfevents_p.h \ qbenchmarkmetric.h \ @@ -70,7 +69,6 @@ SOURCES = \ qabstracttestlogger.cpp \ qbenchmark.cpp \ qbenchmarkmeasurement.cpp \ - qbenchmarkvalgrind.cpp \ qbenchmarkevent.cpp \ qbenchmarkperfevents.cpp \ qbenchmarkmetric.cpp \ @@ -92,6 +90,13 @@ qtConfig(itemmodeltester) { qabstractitemmodeltester.cpp } +qtConfig(valgrind) { + HEADERS += \ + qbenchmarkvalgrind_p.h + SOURCES += \ + qbenchmarkvalgrind.cpp +} + DEFINES *= QT_NO_CAST_TO_ASCII \ QT_NO_CAST_FROM_ASCII \ QT_NO_FOREACH \ -- cgit v1.2.3 From 001ba40e19fa71d05fbac9c059309df40801e89c Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Tue, 14 May 2019 19:24:13 +0200 Subject: QMessageLogContext: rename and improve copy() The "copy" name led me to mis-believe that it was a workaround to the class being non-copiable, and was missing copying a data member. This is instead deliberate; so rename the function to "copyContextFrom", documenting that version won't be copied. The function is still private API, so actually make it private; QMessageLogContext already befriended the only user. Finally, make it return *this (so that it can be chained, if necessary) and noexcept. Change-Id: I3deb3c8edc863a88ac0c37467b144ec2e20db5ca Reviewed-by: Marc Mutz Reviewed-by: Thiago Macieira --- src/corelib/global/qlogging.cpp | 41 +++++++++++++++++++++++------------------ src/corelib/global/qlogging.h | 4 ++-- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 4941ca45aa..292a459e5d 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -439,7 +439,7 @@ void QMessageLogger::debug(const QLoggingCategory &cat, const char *msg, ...) co return; QMessageLogContext ctxt; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); va_list ap; @@ -466,7 +466,7 @@ void QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc, return; QMessageLogContext ctxt; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); va_list ap; @@ -489,7 +489,7 @@ QDebug QMessageLogger::debug() const { QDebug dbg = QDebug(QtDebugMsg); QMessageLogContext &ctxt = dbg.stream->context; - ctxt.copy(context); + ctxt.copyContextFrom(context); return dbg; } @@ -506,7 +506,7 @@ QDebug QMessageLogger::debug(const QLoggingCategory &cat) const dbg.stream->message_output = false; QMessageLogContext &ctxt = dbg.stream->context; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); return dbg; @@ -550,7 +550,7 @@ void QMessageLogger::info(const QLoggingCategory &cat, const char *msg, ...) con return; QMessageLogContext ctxt; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); va_list ap; @@ -577,7 +577,7 @@ void QMessageLogger::info(QMessageLogger::CategoryFunction catFunc, return; QMessageLogContext ctxt; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); va_list ap; @@ -601,7 +601,7 @@ QDebug QMessageLogger::info() const { QDebug dbg = QDebug(QtInfoMsg); QMessageLogContext &ctxt = dbg.stream->context; - ctxt.copy(context); + ctxt.copyContextFrom(context); return dbg; } @@ -618,7 +618,7 @@ QDebug QMessageLogger::info(const QLoggingCategory &cat) const dbg.stream->message_output = false; QMessageLogContext &ctxt = dbg.stream->context; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); return dbg; @@ -668,7 +668,7 @@ void QMessageLogger::warning(const QLoggingCategory &cat, const char *msg, ...) return; QMessageLogContext ctxt; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); va_list ap; @@ -695,7 +695,7 @@ void QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc, return; QMessageLogContext ctxt; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); va_list ap; @@ -717,7 +717,7 @@ QDebug QMessageLogger::warning() const { QDebug dbg = QDebug(QtWarningMsg); QMessageLogContext &ctxt = dbg.stream->context; - ctxt.copy(context); + ctxt.copyContextFrom(context); return dbg; } @@ -733,7 +733,7 @@ QDebug QMessageLogger::warning(const QLoggingCategory &cat) const dbg.stream->message_output = false; QMessageLogContext &ctxt = dbg.stream->context; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); return dbg; @@ -784,7 +784,7 @@ void QMessageLogger::critical(const QLoggingCategory &cat, const char *msg, ...) return; QMessageLogContext ctxt; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); va_list ap; @@ -811,7 +811,7 @@ void QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc, return; QMessageLogContext ctxt; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); va_list ap; @@ -833,7 +833,7 @@ QDebug QMessageLogger::critical() const { QDebug dbg = QDebug(QtCriticalMsg); QMessageLogContext &ctxt = dbg.stream->context; - ctxt.copy(context); + ctxt.copyContextFrom(context); return dbg; } @@ -850,7 +850,7 @@ QDebug QMessageLogger::critical(const QLoggingCategory &cat) const dbg.stream->message_output = false; QMessageLogContext &ctxt = dbg.stream->context; - ctxt.copy(context); + ctxt.copyContextFrom(context); ctxt.category = cat.categoryName(); return dbg; @@ -2108,15 +2108,20 @@ void qSetMessagePattern(const QString &pattern) /*! - Copies context information from \a logContext into this QMessageLogContext + Copies context information from \a logContext into this QMessageLogContext. + Returns a reference to this object. + + Note that the version is \b not copied, only the context information. + \internal */ -void QMessageLogContext::copy(const QMessageLogContext &logContext) +QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext &logContext) noexcept { this->category = logContext.category; this->file = logContext.file; this->line = logContext.line; this->function = logContext.function; + return *this; } /*! diff --git a/src/corelib/global/qlogging.h b/src/corelib/global/qlogging.h index 8f39780112..14c5d66bcd 100644 --- a/src/corelib/global/qlogging.h +++ b/src/corelib/global/qlogging.h @@ -68,8 +68,6 @@ public: Q_DECL_CONSTEXPR QMessageLogContext(const char *fileName, int lineNumber, const char *functionName, const char *categoryName) : version(2), line(lineNumber), file(fileName), function(functionName), category(categoryName) {} - void copy(const QMessageLogContext &logContext); - int version; int line; const char *file; @@ -77,6 +75,8 @@ public: const char *category; private: + QMessageLogContext ©ContextFrom(const QMessageLogContext &logContext) noexcept; + friend class QMessageLogger; friend class QDebug; }; -- cgit v1.2.3 From 4d83d379430d5c26c0711c1c8789b80eaaa3addb Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 13 May 2019 16:27:21 +0200 Subject: QMessageLogContext: simplify construction By using NSDMI. Change-Id: I171133b07ba2c7050e0d279caff0c393e03df182 Reviewed-by: Marc Mutz Reviewed-by: Thiago Macieira --- src/corelib/global/qlogging.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/corelib/global/qlogging.h b/src/corelib/global/qlogging.h index 14c5d66bcd..4a528a2973 100644 --- a/src/corelib/global/qlogging.h +++ b/src/corelib/global/qlogging.h @@ -63,16 +63,15 @@ class QMessageLogContext { Q_DISABLE_COPY(QMessageLogContext) public: - Q_DECL_CONSTEXPR QMessageLogContext() - : version(2), line(0), file(nullptr), function(nullptr), category(nullptr) {} - Q_DECL_CONSTEXPR QMessageLogContext(const char *fileName, int lineNumber, const char *functionName, const char *categoryName) - : version(2), line(lineNumber), file(fileName), function(functionName), category(categoryName) {} - - int version; - int line; - const char *file; - const char *function; - const char *category; + Q_DECL_CONSTEXPR QMessageLogContext() noexcept = default; + Q_DECL_CONSTEXPR QMessageLogContext(const char *fileName, int lineNumber, const char *functionName, const char *categoryName) noexcept + : line(lineNumber), file(fileName), function(functionName), category(categoryName) {} + + int version = 2; + int line = 0; + const char *file = nullptr; + const char *function = nullptr; + const char *category = nullptr; private: QMessageLogContext ©ContextFrom(const QMessageLogContext &logContext) noexcept; -- cgit v1.2.3 From fe4a7de238bef3f632827cbc12ddd576ec0ce76d Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Sun, 12 May 2019 14:00:50 +0900 Subject: Headers cleanup in mac style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Solve many duplication between _p_p.h and .cpp, sorted by module and header name, and move headers for each features at the end of includes. Change-Id: Ice9189c10d062bc473258b7ace279df057102167 Reviewed-by: David Faure Reviewed-by: Tor Arne Vestbø --- src/plugins/styles/mac/qmacstyle_mac.mm | 96 +++++------------------ src/plugins/styles/mac/qmacstyle_mac_p_p.h | 119 +++++++++++++++-------------- 2 files changed, 80 insertions(+), 135 deletions(-) diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 392368a40b..e9f046fcfa 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -50,92 +50,30 @@ #define QMAC_QAQUASTYLE_SIZE_CONSTRAIN //#define DEBUG_SIZE_CONSTRAINT -#include -#if QT_CONFIG(tabbar) -#include -#endif -#include -#include -#include -#if QT_CONFIG(combobox) -#include -#include -#endif -#if QT_CONFIG(dialogbuttonbox) -#include -#endif -#if QT_CONFIG(dockwidget) -#include -#endif -#include -#include -#include -#include -#include -#include -#if QT_CONFIG(lineedit) -#include -#endif -#if QT_CONFIG(mainwindow) -#include -#endif +#include +#include +#include + +#include + +#include +#include +#include + +#include + #if QT_CONFIG(mdiarea) -#include -#endif -#if QT_CONFIG(menubar) -#include -#endif -#include -#include -#include -#include -#if QT_CONFIG(progressbar) -#include -#endif -#if QT_CONFIG(pushbutton) -#include -#endif -#include -#if QT_CONFIG(rubberband) -#include +#include #endif #if QT_CONFIG(scrollbar) -#include -#endif -#if QT_CONFIG(sizegrip) -#include -#endif -#include -#include -#if QT_CONFIG(toolbutton) -#include +#include #endif -#if QT_CONFIG(treeview) -#include -#endif -#if QT_CONFIG(tableview) -#include +#if QT_CONFIG(tabbar) +#include #endif -#include #if QT_CONFIG(wizard) -#include -#endif -#include -#if QT_CONFIG(datetimeedit) -#include +#include #endif -#include -#include -#if QT_CONFIG(graphicsview) -#include -#endif -#include -#include -#include -#include -#include -#include -#include QT_USE_NAMESPACE diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h index dd99cf4bb5..6e7004485c 100644 --- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h +++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h @@ -41,98 +41,105 @@ #ifndef QMACSTYLE_MAC_P_P_H #define QMACSTYLE_MAC_P_P_H -#include -#include #include "qmacstyle_mac_p.h" -#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if QT_CONFIG(checkbox) +#include +#endif #if QT_CONFIG(combobox) -#include +#include +#include #endif -#include -#include -#include -#include -#if QT_CONFIG(checkbox) -#include +#if QT_CONFIG(datetimeedit) +#include #endif -#include #if QT_CONFIG(dialogbuttonbox) -#include +#include #endif #if QT_CONFIG(dockwidget) -#include +#include +#endif +#if QT_CONFIG(graphicsview) +#include +#include #endif -#include -#include -#include #if QT_CONFIG(groupbox) -#include +#include +#endif +#if QT_CONFIG(itemviews) +#include #endif -#include -#include -#include #if QT_CONFIG(lineedit) -#include +#include #endif #if QT_CONFIG(listview) -#include +#include #endif #if QT_CONFIG(mainwindow) -#include +#include #endif -#include #if QT_CONFIG(menubar) -#include +#include #endif -#include -#include -#include -#include #if QT_CONFIG(progressbar) -#include +#include #endif #if QT_CONFIG(pushbutton) -#include +#include #endif -#include +#include #if QT_CONFIG(rubberband) -#include +#include #endif #if QT_CONFIG(sizegrip) -#include +#include #endif #if QT_CONFIG(spinbox) -#include +#include #endif #if QT_CONFIG(splitter) -#include +#include +#endif +#if QT_CONFIG(tableview) +#include #endif -#include -#include -#include #if QT_CONFIG(toolbar) -#include +#include #endif #if QT_CONFIG(toolbutton) -#include +#include #endif #if QT_CONFIG(treeview) -#include -#endif -#if QT_CONFIG(tableview) -#include +#include #endif -#include -#if QT_CONFIG(datetimeedit) -#include -#endif -#include -#include -#include -#include -#include - - // // W A R N I N G -- cgit v1.2.3 From 12e0c7cbe0be22c288413080a1d1bd3beafb3008 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Sun, 26 May 2019 20:23:45 +0900 Subject: Fix network build without feature.networkproxy Change-Id: I832db8e9e13b93d7613bdf890fa6c16be78b3b28 Reviewed-by: Timur Pocheptsov --- src/network/access/qhttpnetworkconnection.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index cb4c722eb5..2e38ac2dcf 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -600,6 +600,7 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket, } } +#if QT_CONFIG(networkproxy) // Send "Proxy-Authorization" header, but not if it's NTLM and the socket is already authenticated. if (channels[i].proxyAuthMethod != QAuthenticatorPrivate::None) { if (!(channels[i].proxyAuthMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 407)) { @@ -611,6 +612,7 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket, } } } +#endif // QT_CONFIG(networkproxy) } QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetworkRequest &request) -- cgit v1.2.3 From 2c8fa9700cb1eb5f1587bec46b7060ec93c6b1d2 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 10 May 2019 20:20:00 +0200 Subject: Support clicking to toggle checkboxes in QTextEdit Add QAbstractTextDocumentLayout::markerAt(pos) for hit testing. (Qt Quick TextEdit needs it too.) Finds out whether the position corresponds to a marker on a paragraph. I.e. it finds checkboxes in GitHub-flavored markdown. This enables editor classes to toggle checkboxes by clicking them. Use it in QTextEdit to add the checkbox toggling feature. Also show the "pointing finger" cursor when hovering a toggleable checkbox. Change-Id: I036c967ab45e14c836272eac2cc7c7d652543c89 Reviewed-by: Gatis Paeglis --- src/gui/text/qabstracttextdocumentlayout.cpp | 31 +++++++++++++++++++++++ src/gui/text/qabstracttextdocumentlayout.h | 1 + src/widgets/widgets/qtextedit.cpp | 17 +++++++++++++ src/widgets/widgets/qtextedit.h | 1 + src/widgets/widgets/qtextedit_p.h | 3 +++ src/widgets/widgets/qwidgettextcontrol.cpp | 38 ++++++++++++++++++++++++++++ src/widgets/widgets/qwidgettextcontrol_p.h | 3 +++ src/widgets/widgets/qwidgettextcontrol_p_p.h | 2 ++ 8 files changed, 96 insertions(+) diff --git a/src/gui/text/qabstracttextdocumentlayout.cpp b/src/gui/text/qabstracttextdocumentlayout.cpp index 2278378613..5263ece87c 100644 --- a/src/gui/text/qabstracttextdocumentlayout.cpp +++ b/src/gui/text/qabstracttextdocumentlayout.cpp @@ -41,6 +41,7 @@ #include #include "qtextdocument_p.h" #include "qtextengine_p.h" +#include "qtextlist.h" #include "qabstracttextdocumentlayout_p.h" @@ -649,6 +650,36 @@ QTextFormat QAbstractTextDocumentLayout::formatAt(const QPointF &pos) const return pieceTable->formatCollection()->format(it->format); } +/*! + \since 5.14 + + Returns the block (probably a list item) whose \l{QTextBlockFormat::marker()}{marker} + is found at the given position \a pos. +*/ +QTextBlock QAbstractTextDocumentLayout::blockWithMarkerAt(const QPointF &pos) const +{ + QTextBlock block = document()->firstBlock(); + while (block.isValid()) { + if (block.blockFormat().marker() != QTextBlockFormat::NoMarker) { + QRectF blockBr = blockBoundingRect(block); + QTextBlockFormat blockFmt = block.blockFormat(); + QFontMetrics fm(block.charFormat().font()); + qreal totalIndent = blockFmt.indent() + blockFmt.leftMargin() + blockFmt.textIndent(); + if (block.textList()) + totalIndent += block.textList()->format().indent() * 40; + QRectF adjustedBr = blockBr.adjusted(totalIndent - fm.height(), 0, totalIndent - blockBr.width(), fm.height() - blockBr.height()); + if (adjustedBr.contains(pos)) { + //qDebug() << "hit block" << block.text() << blockBr << adjustedBr << "marker" << block.blockFormat().marker() + // << "font" << block.charFormat().font() << "adj" << lineHeight << totalIndent; + if (block.blockFormat().hasProperty(QTextFormat::BlockMarker)) + return block; + } + } + block = block.next(); + } + return QTextBlock(); +} + /*! \fn QRectF QAbstractTextDocumentLayout::frameBoundingRect(QTextFrame *frame) const diff --git a/src/gui/text/qabstracttextdocumentlayout.h b/src/gui/text/qabstracttextdocumentlayout.h index 3371401420..397dcd37d4 100644 --- a/src/gui/text/qabstracttextdocumentlayout.h +++ b/src/gui/text/qabstracttextdocumentlayout.h @@ -87,6 +87,7 @@ public: QString anchorAt(const QPointF& pos) const; QString imageAt(const QPointF &pos) const; QTextFormat formatAt(const QPointF &pos) const; + QTextBlock blockWithMarkerAt(const QPointF &pos) const; virtual int pageCount() const = 0; virtual QSizeF documentSize() const = 0; diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp index 5f734258b2..01f7c34f93 100644 --- a/src/widgets/widgets/qtextedit.cpp +++ b/src/widgets/widgets/qtextedit.cpp @@ -167,6 +167,7 @@ void QTextEditPrivate::init(const QString &html) QObject::connect(control, SIGNAL(copyAvailable(bool)), q, SIGNAL(copyAvailable(bool))); QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(_q_cursorPositionChanged())); + QObject::connect(control, SIGNAL(blockMarkerHovered(QTextBlock)), q, SLOT(_q_hoveredBlockWithMarkerChanged(QTextBlock))); QObject::connect(control, SIGNAL(textChanged()), q, SLOT(updateMicroFocus())); @@ -187,6 +188,7 @@ void QTextEditPrivate::init(const QString &html) vbar->setSingleStep(20); viewport->setBackgroundRole(QPalette::Base); + q->setMouseTracking(true); q->setAcceptDrops(true); q->setFocusPolicy(Qt::StrongFocus); q->setAttribute(Qt::WA_KeyCompression); @@ -228,6 +230,21 @@ void QTextEditPrivate::_q_cursorPositionChanged() #endif } +void QTextEditPrivate::_q_hoveredBlockWithMarkerChanged(const QTextBlock &block) +{ + Q_Q(QTextEdit); + Qt::CursorShape cursor = cursorToRestoreAfterHover; + if (block.isValid() && !q->isReadOnly()) { + QTextBlockFormat::MarkerType marker = block.blockFormat().marker(); + if (marker != QTextBlockFormat::NoMarker) { + if (viewport->cursor().shape() != Qt::PointingHandCursor) + cursorToRestoreAfterHover = viewport->cursor().shape(); + cursor = Qt::PointingHandCursor; + } + } + viewport->setCursor(cursor); +} + void QTextEditPrivate::pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode) { QTextCursor cursor = control->textCursor(); diff --git a/src/widgets/widgets/qtextedit.h b/src/widgets/widgets/qtextedit.h index 3b7e610786..09ef44b7b2 100644 --- a/src/widgets/widgets/qtextedit.h +++ b/src/widgets/widgets/qtextedit.h @@ -331,6 +331,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_adjustScrollbars()) Q_PRIVATE_SLOT(d_func(), void _q_ensureVisible(const QRectF &)) Q_PRIVATE_SLOT(d_func(), void _q_cursorPositionChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_hoveredBlockWithMarkerChanged(const QTextBlock &)) friend class QTextEditControl; friend class QTextDocument; friend class QWidgetTextControl; diff --git a/src/widgets/widgets/qtextedit_p.h b/src/widgets/widgets/qtextedit_p.h index c4ee75c78d..f7b4d15318 100644 --- a/src/widgets/widgets/qtextedit_p.h +++ b/src/widgets/widgets/qtextedit_p.h @@ -104,6 +104,7 @@ public: void _q_currentCharFormatChanged(const QTextCharFormat &format); void _q_cursorPositionChanged(); + void _q_hoveredBlockWithMarkerChanged(const QTextBlock &block); void updateDefaultTextOption(); @@ -136,6 +137,8 @@ public: QString placeholderText; + Qt::CursorShape cursorToRestoreAfterHover = Qt::IBeamCursor; + #ifdef QT_KEYPAD_NAVIGATION QBasicTimer deleteAllTimer; #endif diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index f85c7cdc6d..af3b03cd9e 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -1581,6 +1581,11 @@ void QWidgetTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton butto e->ignore(); return; } + bool wasValid = blockWithMarkerUnderMouse.isValid(); + blockWithMarkerUnderMouse = q->blockWithMarkerAt(pos); + if (wasValid != blockWithMarkerUnderMouse.isValid()) + emit q->blockMarkerHovered(blockWithMarkerUnderMouse); + cursorIsFocusIndicator = false; const QTextCursor oldSelection = cursor; @@ -1599,6 +1604,8 @@ void QWidgetTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton butto selectedBlockOnTrippleClick = cursor; anchorOnMousePress = QString(); + blockWithMarkerUnderMouse = QTextBlock(); + emit q->blockMarkerHovered(blockWithMarkerUnderMouse); trippleClickTimer.stop(); } else { @@ -1738,6 +1745,11 @@ void QWidgetTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button } selectionChanged(true); repaintOldAndNewSelection(oldSelection); + } else { + bool wasValid = blockWithMarkerUnderMouse.isValid(); + blockWithMarkerUnderMouse = q->blockWithMarkerAt(mousePos); + if (wasValid != blockWithMarkerUnderMouse.isValid()) + emit q->blockMarkerHovered(blockWithMarkerUnderMouse); } sendMouseEventToInputContext(e, QEvent::MouseMove, button, mousePos, modifiers, buttons, globalPos); @@ -1787,6 +1799,26 @@ void QWidgetTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton but emit q->microFocusChanged(); } + // toggle any checkbox that the user clicks + if ((interactionFlags & Qt::TextEditable) && (button & Qt::LeftButton) && + (blockWithMarkerUnderMouse.isValid()) && !cursor.hasSelection()) { + QTextBlock markerBlock = q->blockWithMarkerAt(pos); + if (markerBlock == blockWithMarkerUnderMouse) { + auto fmt = blockWithMarkerUnderMouse.blockFormat(); + switch (fmt.marker()) { + case QTextBlockFormat::Unchecked : + fmt.setMarker(QTextBlockFormat::Checked); + break; + case QTextBlockFormat::Checked: + fmt.setMarker(QTextBlockFormat::Unchecked); + break; + default: + break; + } + cursor.setBlockFormat(fmt); + } + } + if (interactionFlags & Qt::LinksAccessibleByMouse) { if (!(button & Qt::LeftButton)) return; @@ -2385,6 +2417,12 @@ QString QWidgetTextControl::anchorAtCursor() const return d->anchorForCursor(d->cursor); } +QTextBlock QWidgetTextControl::blockWithMarkerAt(const QPointF &pos) const +{ + Q_D(const QWidgetTextControl); + return d->doc->documentLayout()->blockWithMarkerAt(pos); +} + bool QWidgetTextControl::overwriteMode() const { Q_D(const QWidgetTextControl); diff --git a/src/widgets/widgets/qwidgettextcontrol_p.h b/src/widgets/widgets/qwidgettextcontrol_p.h index e521e7b356..59bf5466e6 100644 --- a/src/widgets/widgets/qwidgettextcontrol_p.h +++ b/src/widgets/widgets/qwidgettextcontrol_p.h @@ -150,6 +150,8 @@ public: QString anchorAtCursor() const; + QTextBlock blockWithMarkerAt(const QPointF &pos) const; + bool overwriteMode() const; void setOverwriteMode(bool overwrite); @@ -242,6 +244,7 @@ Q_SIGNALS: void microFocusChanged(); void linkActivated(const QString &link); void linkHovered(const QString &); + void blockMarkerHovered(const QTextBlock &block); void modificationChanged(bool m); public: diff --git a/src/widgets/widgets/qwidgettextcontrol_p_p.h b/src/widgets/widgets/qwidgettextcontrol_p_p.h index 6ccdfafe2b..c77a31bedf 100644 --- a/src/widgets/widgets/qwidgettextcontrol_p_p.h +++ b/src/widgets/widgets/qwidgettextcontrol_p_p.h @@ -55,6 +55,7 @@ #include "QtGui/qtextdocumentfragment.h" #include "QtGui/qtextcursor.h" #include "QtGui/qtextformat.h" +#include "QtGui/qtextobject.h" #if QT_CONFIG(menu) #include "QtWidgets/qmenu.h" #endif @@ -227,6 +228,7 @@ public: QString highlightedAnchor; // Anchor below cursor QString anchorOnMousePress; + QTextBlock blockWithMarkerUnderMouse; bool hadSelectionOnMousePress; bool ignoreUnusedNavigationEvents; -- cgit v1.2.3 From 7224d0e427d71e559b928c44634839b4791c1416 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 13 May 2019 12:58:37 +0200 Subject: QTextMarkdownImporter: don't keep heading level on following list item When reading a document like # heading - list item and then re-writing it, it turned into # heading - # list item because QTextCursor::insertList() simply calls QTextCursor::insertBlock(), thus inheriting block format from the previous block, without an opportunity to explicitly define the block format. So be more consistent: use QTextMarkdownImporter::insertBlock() for blocks inside list items too. Now it fully defines blockFormat first, then inserts the block, and then adds it to the current list only when the "paragraph" is actually the list item's text (but not when it's a continuation paragraph). Also, be prepared for applying and removing block markers to arbitrary blocks, just in case (they might be useful for block quotes, for example). Change-Id: I391820af9b65e75abce12abab45d2477c49c86ac Reviewed-by: Gatis Paeglis --- src/gui/text/qtextmarkdownimporter.cpp | 96 ++++++++++++---------- src/gui/text/qtextmarkdownimporter_p.h | 11 +-- .../qtextmarkdownwriter/data/headingsAndLists.md | 12 +++ .../tst_qtextmarkdownwriter.cpp | 1 + 4 files changed, 71 insertions(+), 49 deletions(-) create mode 100644 tests/auto/gui/text/qtextmarkdownwriter/data/headingsAndLists.md diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp index 8c80a3f0c7..b96acba0e6 100644 --- a/src/gui/text/qtextmarkdownimporter.cpp +++ b/src/gui/text/qtextmarkdownimporter.cpp @@ -151,25 +151,16 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det) m_blockType = blockType; switch (blockType) { case MD_BLOCK_P: - if (m_listStack.isEmpty()) { - m_needsInsertBlock = true; + if (!m_listStack.isEmpty()) + qCDebug(lcMD, m_listItem ? "P of LI at level %d" : "P continuation inside LI at level %d", m_listStack.count()); + else qCDebug(lcMD, "P"); - } else { - if (m_emptyListItem) { - qCDebug(lcMD, "LI text block at level %d -> BlockIndent %d", - m_listStack.count(), m_cursor->blockFormat().indent()); - m_emptyListItem = false; - } else { - qCDebug(lcMD, "P inside LI at level %d", m_listStack.count()); - m_needsInsertBlock = true; - } - } + m_needsInsertBlock = true; break; - case MD_BLOCK_QUOTE: { + case MD_BLOCK_QUOTE: ++m_blockQuoteDepth; qCDebug(lcMD, "QUOTE level %d", m_blockQuoteDepth); break; - } case MD_BLOCK_CODE: { MD_BLOCK_CODE_DETAIL *detail = static_cast(det); m_codeBlock = true; @@ -194,51 +185,40 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det) qCDebug(lcMD, "H%d", detail->level); } break; case MD_BLOCK_LI: { - m_needsInsertBlock = false; - MD_BLOCK_LI_DETAIL *detail = static_cast(det); - QTextList *list = m_listStack.top(); - QTextBlockFormat bfmt = list->item(list->count() - 1).blockFormat(); - bfmt.setMarker(detail->is_task ? - (detail->task_mark == ' ' ? QTextBlockFormat::Unchecked : QTextBlockFormat::Checked) : - QTextBlockFormat::NoMarker); - if (!m_emptyList) { - m_cursor->insertBlock(bfmt, QTextCharFormat()); - list->add(m_cursor->block()); - } - m_cursor->setBlockFormat(bfmt); - qCDebug(lcMD) << (m_emptyList ? "LI (first in list)" : "LI"); - m_emptyList = false; // Avoid insertBlock for the first item (because insertList already did that) + m_needsInsertBlock = true; m_listItem = true; - m_emptyListItem = true; + MD_BLOCK_LI_DETAIL *detail = static_cast(det); + m_markerType = detail->is_task ? + (detail->task_mark == ' ' ? QTextBlockFormat::Unchecked : QTextBlockFormat::Checked) : + QTextBlockFormat::NoMarker; + qCDebug(lcMD) << "LI"; } break; case MD_BLOCK_UL: { MD_BLOCK_UL_DETAIL *detail = static_cast(det); - QTextListFormat fmt; - fmt.setIndent(m_listStack.count() + 1); + m_listFormat = QTextListFormat(); + m_listFormat.setIndent(m_listStack.count() + 1); switch (detail->mark) { case '*': - fmt.setStyle(QTextListFormat::ListCircle); + m_listFormat.setStyle(QTextListFormat::ListCircle); break; case '+': - fmt.setStyle(QTextListFormat::ListSquare); + m_listFormat.setStyle(QTextListFormat::ListSquare); break; default: // including '-' - fmt.setStyle(QTextListFormat::ListDisc); + m_listFormat.setStyle(QTextListFormat::ListDisc); break; } qCDebug(lcMD, "UL %c level %d", detail->mark, m_listStack.count()); - m_listStack.push(m_cursor->insertList(fmt)); - m_emptyList = true; + m_needsInsertList = true; } break; case MD_BLOCK_OL: { MD_BLOCK_OL_DETAIL *detail = static_cast(det); - QTextListFormat fmt; - fmt.setIndent(m_listStack.count() + 1); - fmt.setNumberSuffix(QChar::fromLatin1(detail->mark_delimiter)); - fmt.setStyle(QTextListFormat::ListDecimal); + m_listFormat = QTextListFormat(); + m_listFormat.setIndent(m_listStack.count() + 1); + m_listFormat.setNumberSuffix(QChar::fromLatin1(detail->mark_delimiter)); + m_listFormat.setStyle(QTextListFormat::ListDecimal); qCDebug(lcMD, "OL xx%d level %d", detail->mark_delimiter, m_listStack.count()); - m_listStack.push(m_cursor->insertList(fmt)); - m_emptyList = true; + m_needsInsertList = true; } break; case MD_BLOCK_TD: { MD_BLOCK_TD_DETAIL *detail = static_cast(det); @@ -299,6 +279,9 @@ int QTextMarkdownImporter::cbLeaveBlock(int blockType, void *detail) { Q_UNUSED(detail) switch (blockType) { + case MD_BLOCK_P: + m_listItem = false; + break; case MD_BLOCK_UL: case MD_BLOCK_OL: qCDebug(lcMD, "list at level %d ended", m_listStack.count()); @@ -525,19 +508,32 @@ int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size) return 0; // no error } +/*! + Insert a new block based on stored state. + + m_cursor cannot store the state for the _next_ block ahead of time, because + m_cursor->setBlockFormat() controls the format of the block that the cursor + is already in; so cbLeaveBlock() cannot call setBlockFormat() without + altering the block that was just added. Therefore cbLeaveBlock() and the + following cbEnterBlock() set variables to remember what formatting should + come next, and insertBlock() is called just before the actual text + insertion, to create a new block with the right formatting. +*/ void QTextMarkdownImporter::insertBlock() { QTextCharFormat charFormat; if (!m_spanFormatStack.isEmpty()) charFormat = m_spanFormatStack.top(); QTextBlockFormat blockFormat; + if (!m_listStack.isEmpty() && !m_needsInsertList && m_listItem) { + QTextList *list = m_listStack.top(); + blockFormat = list->item(list->count() - 1).blockFormat(); + } if (m_blockQuoteDepth) { blockFormat.setProperty(QTextFormat::BlockQuoteLevel, m_blockQuoteDepth); blockFormat.setLeftMargin(BlockQuoteIndent * m_blockQuoteDepth); blockFormat.setRightMargin(BlockQuoteIndent); } - if (m_listStack.count()) - blockFormat.setIndent(m_listStack.count()); if (m_codeBlock) { blockFormat.setProperty(QTextFormat::BlockCodeLanguage, m_blockCodeLanguage); charFormat.setFont(m_monoFont); @@ -545,7 +541,19 @@ void QTextMarkdownImporter::insertBlock() blockFormat.setTopMargin(m_paragraphMargin); blockFormat.setBottomMargin(m_paragraphMargin); } + if (m_markerType == QTextBlockFormat::NoMarker) + blockFormat.clearProperty(QTextFormat::BlockMarker); + else + blockFormat.setMarker(m_markerType); + if (!m_listStack.isEmpty()) + blockFormat.setIndent(m_listStack.count()); m_cursor->insertBlock(blockFormat, charFormat); + if (m_needsInsertList) { + m_listStack.push(m_cursor->createList(m_listFormat)); + } else if (!m_listStack.isEmpty() && m_listItem) { + m_listStack.top()->add(m_cursor->block()); + } + m_needsInsertList = false; m_needsInsertBlock = false; } diff --git a/src/gui/text/qtextmarkdownimporter_p.h b/src/gui/text/qtextmarkdownimporter_p.h index d62f1cf7dd..f905aa0f87 100644 --- a/src/gui/text/qtextmarkdownimporter_p.h +++ b/src/gui/text/qtextmarkdownimporter_p.h @@ -123,14 +123,15 @@ private: int m_tableRowCount = 0; int m_tableCol = -1; // because relative cell movements (e.g. m_cursor->movePosition(QTextCursor::NextCell)) don't work int m_paragraphMargin = 0; - Features m_features; int m_blockType = 0; - bool m_emptyList = false; // true when the last thing we did was insertList - bool m_listItem = false; - bool m_emptyListItem = false; + Features m_features; + QTextListFormat m_listFormat; + QTextBlockFormat::MarkerType m_markerType = QTextBlockFormat::NoMarker; + bool m_needsInsertBlock = false; + bool m_needsInsertList = false; + bool m_listItem = false; // true from the beginning of LI to the end of the first P bool m_codeBlock = false; bool m_imageSpan = false; - bool m_needsInsertBlock = false; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QTextMarkdownImporter::Features) diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/headingsAndLists.md b/tests/auto/gui/text/qtextmarkdownwriter/data/headingsAndLists.md new file mode 100644 index 0000000000..d5d14fb168 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/headingsAndLists.md @@ -0,0 +1,12 @@ +# heading 1 + +- list item 1 +- list item 2 + +## heading 2 + +1) list item 1 +2) list item 2 + +the end paragraph + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp index 9998794762..b14e810430 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp +++ b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp @@ -357,6 +357,7 @@ void tst_QTextMarkdownWriter::rewriteDocument_data() QTest::newRow("block quotes") << "blockquotes.md"; QTest::newRow("example") << "example.md"; + QTest::newRow("list items after headings") << "headingsAndLists.md"; } void tst_QTextMarkdownWriter::rewriteDocument() -- cgit v1.2.3 From 280d679c556ab8ead4748a627d7cd4c1950027fb Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 20 May 2019 11:50:26 +0200 Subject: QTextMarkdownWriter: fix some bad cases with word wrap If any non-breakable content (such as a link) already went past 80 columns, or if a word ended on column 80, it didn't wrap the rest of the paragraph following. Change-Id: I27dc0474f18892c34ee2514ea6d5070dae29424f Reviewed-by: Gatis Paeglis --- src/gui/text/qtextmarkdownwriter.cpp | 21 ++++++++++++++++++--- .../text/qtextmarkdownwriter/data/blockquotes.md | 3 ++- .../gui/text/qtextmarkdownwriter/data/wordWrap.md | 13 +++++++++++++ .../qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp | 1 + 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 tests/auto/gui/text/qtextmarkdownwriter/data/wordWrap.md diff --git a/src/gui/text/qtextmarkdownwriter.cpp b/src/gui/text/qtextmarkdownwriter.cpp index f180098db2..02643acdca 100644 --- a/src/gui/text/qtextmarkdownwriter.cpp +++ b/src/gui/text/qtextmarkdownwriter.cpp @@ -212,10 +212,19 @@ QTextMarkdownWriter::ListInfo QTextMarkdownWriter::listInfo(QTextList *list) static int nearestWordWrapIndex(const QString &s, int before) { before = qMin(before, s.length()); + int fragBegin = qMax(before - 15, 0); + if (lcMDW().isDebugEnabled()) { + QString frag = s.mid(fragBegin, 30); + qCDebug(lcMDW) << frag << before; + qCDebug(lcMDW) << QString(before - fragBegin, Period) + QLatin1Char('<'); + } for (int i = before - 1; i >= 0; --i) { - if (s.at(i).isSpace()) + if (s.at(i).isSpace()) { + qCDebug(lcMDW) << QString(i - fragBegin, Period) + QLatin1Char('^') << i; return i; + } } + qCDebug(lcMDW, "not possible"); return -1; } @@ -251,7 +260,7 @@ static void maybeEscapeFirstChar(QString &s) int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ignoreFormat) { - int ColumnLimit = 80; + const int ColumnLimit = 80; QTextBlockFormat blockFmt = block.blockFormat(); bool indentedCodeBlock = false; if (block.textList()) { // it's a list-item @@ -419,12 +428,18 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign int fragLen = fragmentText.length(); bool breakingLine = false; while (i < fragLen) { + if (col >= ColumnLimit) { + m_stream << Newline << wrapIndentString; + col = m_wrappedLineIndent; + while (fragmentText[i].isSpace()) + ++i; + } int j = i + ColumnLimit - col; if (j < fragLen) { int wi = nearestWordWrapIndex(fragmentText, j); if (wi < 0) { j = fragLen; - } else { + } else if (wi >= i) { j = wi; breakingLine = true; } diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md index f429fcc21b..44c198fdc5 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md @@ -13,7 +13,8 @@ MacFarlane writes: > > as readable as possible. The idea is that a Markdown-formatted document should > > be publishable as-is, as plain text, without looking like it's been marked up > > with tags or formatting instructions. ( -> > [http://daringfireball.net/projects/markdown/](http://daringfireball.net/projects/markdown/)) +> > [http://daringfireball.net/projects/markdown/](http://daringfireball.net/projects/markdown/) +> > ) > The point can be illustrated by comparing a sample of AsciiDoc with an > equivalent sample of Markdown. Here is a sample of AsciiDoc from the AsciiDoc diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/wordWrap.md b/tests/auto/gui/text/qtextmarkdownwriter/data/wordWrap.md new file mode 100644 index 0000000000..dacb0acf77 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/wordWrap.md @@ -0,0 +1,13 @@ +[The CommonMark Specification](https://spec.commonmark.org/0.29/) is the +conservative formal specification of the Markdown format, while +[GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown) +adds extra features such as task lists and tables. + +Qt owes thanks to the authors of the [MD4C parser](https://github.com/mity/md4c) +for making markdown import possible. The QTextMarkdownWriter class does not +have such dependencies, and also has not yet been tested as extensively, so we +do not yet guarantee that we are able to rewrite every Markdown document that +you are able to read and display with Text or QTextEdit. But you are free to +write [bugs](https://bugreports.qt.io) about any troublesome cases that you +encounter. + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp index b14e810430..acc74a9060 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp +++ b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp @@ -358,6 +358,7 @@ void tst_QTextMarkdownWriter::rewriteDocument_data() QTest::newRow("block quotes") << "blockquotes.md"; QTest::newRow("example") << "example.md"; QTest::newRow("list items after headings") << "headingsAndLists.md"; + QTest::newRow("word wrap") << "wordWrap.md"; } void tst_QTextMarkdownWriter::rewriteDocument() -- cgit v1.2.3 From 5ab6e2ef20fef198d2f1315909c756007a0c6d03 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 22 Apr 2019 06:18:23 +0200 Subject: Update 3rdparty md4c library 0.3.3 plus a few more patches, including the one that adds MD_BLOCK_CODE_DETAIL::fence_char, which will enable smarter rewriting of code blocks (indented vs. fenced). Change-Id: Ibc892369947a8a8edfa4bc20b1df98a5c8153141 Reviewed-by: Gatis Paeglis --- src/3rdparty/md4c/md4c.c | 2355 +++++++++++++++++---------------- src/3rdparty/md4c/md4c.h | 7 +- src/3rdparty/md4c/qt_attribution.json | 4 +- 3 files changed, 1227 insertions(+), 1139 deletions(-) diff --git a/src/3rdparty/md4c/md4c.c b/src/3rdparty/md4c/md4c.c index 13c7bd3433..01e63a5fd2 100644 --- a/src/3rdparty/md4c/md4c.c +++ b/src/3rdparty/md4c/md4c.c @@ -98,6 +98,9 @@ struct MD_CTX_tag { MD_PARSER parser; void* userdata; + /* When this is true, it allows some optimizations. */ + int doc_ends_with_newline; + /* Helper temporary growing buffer. */ CHAR* buffer; unsigned alloc_buffer; @@ -124,17 +127,20 @@ struct MD_CTX_tag { #endif /* For resolving of inline spans. */ - MD_MARKCHAIN mark_chains[8]; -#define PTR_CHAIN ctx->mark_chains[0] -#define TABLECELLBOUNDARIES ctx->mark_chains[1] -#define BACKTICK_OPENERS ctx->mark_chains[2] -#define LOWERTHEN_OPENERS ctx->mark_chains[3] -#define ASTERISK_OPENERS ctx->mark_chains[4] -#define UNDERSCORE_OPENERS ctx->mark_chains[5] -#define TILDE_OPENERS ctx->mark_chains[6] -#define BRACKET_OPENERS ctx->mark_chains[7] -#define OPENERS_CHAIN_FIRST 2 -#define OPENERS_CHAIN_LAST 7 + MD_MARKCHAIN mark_chains[11]; +#define PTR_CHAIN ctx->mark_chains[0] +#define TABLECELLBOUNDARIES ctx->mark_chains[1] +#define ASTERISK_OPENERS_extraword_mod3_0 ctx->mark_chains[2] +#define ASTERISK_OPENERS_extraword_mod3_1 ctx->mark_chains[3] +#define ASTERISK_OPENERS_extraword_mod3_2 ctx->mark_chains[4] +#define ASTERISK_OPENERS_intraword_mod3_0 ctx->mark_chains[5] +#define ASTERISK_OPENERS_intraword_mod3_1 ctx->mark_chains[6] +#define ASTERISK_OPENERS_intraword_mod3_2 ctx->mark_chains[7] +#define UNDERSCORE_OPENERS ctx->mark_chains[8] +#define TILDE_OPENERS ctx->mark_chains[9] +#define BRACKET_OPENERS ctx->mark_chains[10] +#define OPENERS_CHAIN_FIRST 2 +#define OPENERS_CHAIN_LAST 10 int n_table_cell_boundaries; @@ -142,6 +148,12 @@ struct MD_CTX_tag { int unresolved_link_head; int unresolved_link_tail; + /* For resolving raw HTML. */ + OFF html_comment_horizon; + OFF html_proc_instr_horizon; + OFF html_decl_horizon; + OFF html_cdata_horizon; + /* For block analysis. * Notes: * -- It holds MD_BLOCK as well as MD_LINE structures. After each @@ -159,18 +171,16 @@ struct MD_CTX_tag { int n_containers; int alloc_containers; - int last_line_has_list_loosening_effect; - int last_list_item_starts_with_two_blank_lines; - /* Minimal indentation to call the block "indented code block". */ unsigned code_indent_offset; /* Contextual info for line analysis. */ SZ code_fence_length; /* For checking closing fence length. */ int html_block_type; /* For checking closing raw HTML condition. */ + int last_line_has_list_loosening_effect; + int last_list_item_starts_with_two_blank_lines; }; -typedef enum MD_LINETYPE_tag MD_LINETYPE; enum MD_LINETYPE_tag { MD_LINE_BLANK, MD_LINE_HR, @@ -184,6 +194,7 @@ enum MD_LINETYPE_tag { MD_LINE_TABLE, MD_LINE_TABLEUNDERLINE }; +typedef enum MD_LINETYPE_tag MD_LINETYPE; typedef struct MD_LINE_ANALYSIS_tag MD_LINE_ANALYSIS; struct MD_LINE_ANALYSIS_tag { @@ -445,209 +456,212 @@ md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ typedef struct MD_UNICODE_FOLD_INFO_tag MD_UNICODE_FOLD_INFO; struct MD_UNICODE_FOLD_INFO_tag { - int codepoints[3]; + unsigned codepoints[3]; int n_codepoints; }; #if defined MD4C_USE_UTF16 || defined MD4C_USE_UTF8 + /* Binary search over sorted "map" of codepoints. Consecutive sequences + * of codepoints may be encoded in the map by just using the + * (MIN_CODEPOINT | 0x40000000) and (MAX_CODEPOINT | 0x80000000). + * + * Returns index of the found record in the map (in the case of ranges, + * the minimal value is used); or -1 on failure. */ static int - md_is_unicode_whitespace__(int codepoint) + md_unicode_bsearch__(unsigned codepoint, const unsigned* map, size_t map_size) { - /* The ASCII ones are the most frequently used ones, so lets check them first. */ - if(codepoint <= 0x7f) - return ISWHITESPACE_(codepoint); - - /* Check for Unicode codepoints in Zs class above 127. */ - if(codepoint == 0x00a0 || codepoint == 0x1680) - return TRUE; - if(0x2000 <= codepoint && codepoint <= 0x200a) - return TRUE; - if(codepoint == 0x202f || codepoint == 0x205f || codepoint == 0x3000) - return TRUE; + int beg, end; + int pivot_beg, pivot_end; + + beg = 0; + end = (int) map_size-1; + while(beg <= end) { + /* Pivot may be a range, not just a single value. */ + pivot_beg = pivot_end = (beg + end) / 2; + if(map[pivot_end] & 0x40000000) + pivot_end++; + if(map[pivot_beg] & 0x80000000) + pivot_beg--; + + if(codepoint < (map[pivot_beg] & 0x00ffffff)) + end = pivot_beg - 1; + else if(codepoint > (map[pivot_end] & 0x00ffffff)) + beg = pivot_end + 1; + else + return pivot_beg; + } - return FALSE; + return -1; } static int - md_unicode_cmp__(const void* p_codepoint_a, const void* p_codepoint_b) + md_is_unicode_whitespace__(unsigned codepoint) { - return (*(const int*)p_codepoint_a - *(const int*)p_codepoint_b); +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode "Zs" category. + * (generated by scripts/build_whitespace_map.py) */ + static const unsigned WHITESPACE_MAP[] = { + S(0x0020), S(0x00a0), S(0x1680), R(0x2000,0x200a), S(0x202f), S(0x205f), S(0x3000) + }; +#undef R +#undef S + + /* The ASCII ones are the most frequently used ones, also CommonMark + * specification requests few more in this range. */ + if(codepoint <= 0x7f) + return ISWHITESPACE_(codepoint); + + return (md_unicode_bsearch__(codepoint, WHITESPACE_MAP, SIZEOF_ARRAY(WHITESPACE_MAP)) >= 0); } static int - md_is_unicode_punct__(int codepoint) + md_is_unicode_punct__(unsigned codepoint) { - /* non-ASCII (above 127) Unicode punctuation codepoints (classes - * Pc, Pd, Pe, Pf, Pi, Po, Ps). - * - * Warning: Keep the array sorted. - */ - static const int punct_list[] = { - 0x00a1, 0x00a7, 0x00ab, 0x00b6, 0x00b7, 0x00bb, 0x00bf, 0x037e, 0x0387, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f, 0x0589, - 0x058a, 0x05be, 0x05c0, 0x05c3, 0x05c6, 0x05f3, 0x05f4, 0x0609, 0x060a, 0x060c, 0x060d, 0x061b, 0x061e, 0x061f, 0x066a, 0x066b, - 0x066c, 0x066d, 0x06d4, 0x0700, 0x0701, 0x0702, 0x0703, 0x0704, 0x0705, 0x0706, 0x0707, 0x0708, 0x0709, 0x070a, 0x070b, 0x070c, - 0x070d, 0x07f7, 0x07f8, 0x07f9, 0x0830, 0x0831, 0x0832, 0x0833, 0x0834, 0x0835, 0x0836, 0x0837, 0x0838, 0x0839, 0x083a, 0x083b, - 0x083c, 0x083d, 0x083e, 0x085e, 0x0964, 0x0965, 0x0970, 0x0af0, 0x0df4, 0x0e4f, 0x0e5a, 0x0e5b, 0x0f04, 0x0f05, 0x0f06, 0x0f07, - 0x0f08, 0x0f09, 0x0f0a, 0x0f0b, 0x0f0c, 0x0f0d, 0x0f0e, 0x0f0f, 0x0f10, 0x0f11, 0x0f12, 0x0f14, 0x0f3a, 0x0f3b, 0x0f3c, 0x0f3d, - 0x0f85, 0x0fd0, 0x0fd1, 0x0fd2, 0x0fd3, 0x0fd4, 0x0fd9, 0x0fda, 0x104a, 0x104b, 0x104c, 0x104d, 0x104e, 0x104f, 0x10fb, 0x1360, - 0x1361, 0x1362, 0x1363, 0x1364, 0x1365, 0x1366, 0x1367, 0x1368, 0x1400, 0x166d, 0x166e, 0x169b, 0x169c, 0x16eb, 0x16ec, 0x16ed, - 0x1735, 0x1736, 0x17d4, 0x17d5, 0x17d6, 0x17d8, 0x17d9, 0x17da, 0x1800, 0x1801, 0x1802, 0x1803, 0x1804, 0x1805, 0x1806, 0x1807, - 0x1808, 0x1809, 0x180a, 0x1944, 0x1945, 0x1a1e, 0x1a1f, 0x1aa0, 0x1aa1, 0x1aa2, 0x1aa3, 0x1aa4, 0x1aa5, 0x1aa6, 0x1aa8, 0x1aa9, - 0x1aaa, 0x1aab, 0x1aac, 0x1aad, 0x1b5a, 0x1b5b, 0x1b5c, 0x1b5d, 0x1b5e, 0x1b5f, 0x1b60, 0x1bfc, 0x1bfd, 0x1bfe, 0x1bff, 0x1c3b, - 0x1c3c, 0x1c3d, 0x1c3e, 0x1c3f, 0x1c7e, 0x1c7f, 0x1cc0, 0x1cc1, 0x1cc2, 0x1cc3, 0x1cc4, 0x1cc5, 0x1cc6, 0x1cc7, 0x1cd3, 0x2010, - 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201a, 0x201b, 0x201c, 0x201d, 0x201e, 0x201f, 0x2020, - 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, 0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, - 0x2039, 0x203a, 0x203b, 0x203c, 0x203d, 0x203e, 0x203f, 0x2040, 0x2041, 0x2042, 0x2043, 0x2045, 0x2046, 0x2047, 0x2048, 0x2049, - 0x204a, 0x204b, 0x204c, 0x204d, 0x204e, 0x204f, 0x2050, 0x2051, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, 0x2059, 0x205a, - 0x205b, 0x205c, 0x205d, 0x205e, 0x207d, 0x207e, 0x208d, 0x208e, 0x2308, 0x2309, 0x230a, 0x230b, 0x2329, 0x232a, 0x2768, 0x2769, - 0x276a, 0x276b, 0x276c, 0x276d, 0x276e, 0x276f, 0x2770, 0x2771, 0x2772, 0x2773, 0x2774, 0x2775, 0x27c5, 0x27c6, 0x27e6, 0x27e7, - 0x27e8, 0x27e9, 0x27ea, 0x27eb, 0x27ec, 0x27ed, 0x27ee, 0x27ef, 0x2983, 0x2984, 0x2985, 0x2986, 0x2987, 0x2988, 0x2989, 0x298a, - 0x298b, 0x298c, 0x298d, 0x298e, 0x298f, 0x2990, 0x2991, 0x2992, 0x2993, 0x2994, 0x2995, 0x2996, 0x2997, 0x2998, 0x29d8, 0x29d9, - 0x29da, 0x29db, 0x29fc, 0x29fd, 0x2cf9, 0x2cfa, 0x2cfb, 0x2cfc, 0x2cfe, 0x2cff, 0x2d70, 0x2e00, 0x2e01, 0x2e02, 0x2e03, 0x2e04, - 0x2e05, 0x2e06, 0x2e07, 0x2e08, 0x2e09, 0x2e0a, 0x2e0b, 0x2e0c, 0x2e0d, 0x2e0e, 0x2e0f, 0x2e10, 0x2e11, 0x2e12, 0x2e13, 0x2e14, - 0x2e15, 0x2e16, 0x2e17, 0x2e18, 0x2e19, 0x2e1a, 0x2e1b, 0x2e1c, 0x2e1d, 0x2e1e, 0x2e1f, 0x2e20, 0x2e21, 0x2e22, 0x2e23, 0x2e24, - 0x2e25, 0x2e26, 0x2e27, 0x2e28, 0x2e29, 0x2e2a, 0x2e2b, 0x2e2c, 0x2e2d, 0x2e2e, 0x2e30, 0x2e31, 0x2e32, 0x2e33, 0x2e34, 0x2e35, - 0x2e36, 0x2e37, 0x2e38, 0x2e39, 0x2e3a, 0x2e3b, 0x2e3c, 0x2e3d, 0x2e3e, 0x2e3f, 0x2e40, 0x2e41, 0x2e42, 0x2e43, 0x2e44, 0x3001, - 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x300c, 0x300d, 0x300e, 0x300f, 0x3010, 0x3011, 0x3014, 0x3015, 0x3016, 0x3017, - 0x3018, 0x3019, 0x301a, 0x301b, 0x301c, 0x301d, 0x301e, 0x301f, 0x3030, 0x303d, 0x30a0, 0x30fb, 0xa4fe, 0xa4ff, 0xa60d, 0xa60e, - 0xa60f, 0xa673, 0xa67e, 0xa6f2, 0xa6f3, 0xa6f4, 0xa6f5, 0xa6f6, 0xa6f7, 0xa874, 0xa875, 0xa876, 0xa877, 0xa8ce, 0xa8cf, 0xa8f8, - 0xa8f9, 0xa8fa, 0xa8fc, 0xa92e, 0xa92f, 0xa95f, 0xa9c1, 0xa9c2, 0xa9c3, 0xa9c4, 0xa9c5, 0xa9c6, 0xa9c7, 0xa9c8, 0xa9c9, 0xa9ca, - 0xa9cb, 0xa9cc, 0xa9cd, 0xa9de, 0xa9df, 0xaa5c, 0xaa5d, 0xaa5e, 0xaa5f, 0xaade, 0xaadf, 0xaaf0, 0xaaf1, 0xabeb, 0xfd3e, 0xfd3f, - 0xfe10, 0xfe11, 0xfe12, 0xfe13, 0xfe14, 0xfe15, 0xfe16, 0xfe17, 0xfe18, 0xfe19, 0xfe30, 0xfe31, 0xfe32, 0xfe33, 0xfe34, 0xfe35, - 0xfe36, 0xfe37, 0xfe38, 0xfe39, 0xfe3a, 0xfe3b, 0xfe3c, 0xfe3d, 0xfe3e, 0xfe3f, 0xfe40, 0xfe41, 0xfe42, 0xfe43, 0xfe44, 0xfe45, - 0xfe46, 0xfe47, 0xfe48, 0xfe49, 0xfe4a, 0xfe4b, 0xfe4c, 0xfe4d, 0xfe4e, 0xfe4f, 0xfe50, 0xfe51, 0xfe52, 0xfe54, 0xfe55, 0xfe56, - 0xfe57, 0xfe58, 0xfe59, 0xfe5a, 0xfe5b, 0xfe5c, 0xfe5d, 0xfe5e, 0xfe5f, 0xfe60, 0xfe61, 0xfe63, 0xfe68, 0xfe6a, 0xfe6b, 0xff01, - 0xff02, 0xff03, 0xff05, 0xff06, 0xff07, 0xff08, 0xff09, 0xff0a, 0xff0c, 0xff0d, 0xff0e, 0xff0f, 0xff1a, 0xff1b, 0xff1f, 0xff20, - 0xff3b, 0xff3c, 0xff3d, 0xff3f, 0xff5b, 0xff5d, 0xff5f, 0xff60, 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0x10100, 0x10101, 0x10102, - 0x1039f, 0x103d0, 0x1056f, 0x10857, 0x1091f, 0x1093f, 0x10a50, 0x10a51, 0x10a52, 0x10a53, 0x10a54, 0x10a55, 0x10a56, 0x10a57, 0x10a58, 0x10a7f, - 0x10af0, 0x10af1, 0x10af2, 0x10af3, 0x10af4, 0x10af5, 0x10af6, 0x10b39, 0x10b3a, 0x10b3b, 0x10b3c, 0x10b3d, 0x10b3e, 0x10b3f, 0x10b99, 0x10b9a, - 0x10b9b, 0x10b9c, 0x11047, 0x11048, 0x11049, 0x1104a, 0x1104b, 0x1104c, 0x1104d, 0x110bb, 0x110bc, 0x110be, 0x110bf, 0x110c0, 0x110c1, 0x11140, - 0x11141, 0x11142, 0x11143, 0x11174, 0x11175, 0x111c5, 0x111c6, 0x111c7, 0x111c8, 0x111c9, 0x111cd, 0x111db, 0x111dd, 0x111de, 0x111df, 0x11238, - 0x11239, 0x1123a, 0x1123b, 0x1123c, 0x1123d, 0x112a9, 0x1144b, 0x1144c, 0x1144d, 0x1144e, 0x1144f, 0x1145b, 0x1145d, 0x114c6, 0x115c1, 0x115c2, - 0x115c3, 0x115c4, 0x115c5, 0x115c6, 0x115c7, 0x115c8, 0x115c9, 0x115ca, 0x115cb, 0x115cc, 0x115cd, 0x115ce, 0x115cf, 0x115d0, 0x115d1, 0x115d2, - 0x115d3, 0x115d4, 0x115d5, 0x115d6, 0x115d7, 0x11641, 0x11642, 0x11643, 0x11660, 0x11661, 0x11662, 0x11663, 0x11664, 0x11665, 0x11666, 0x11667, - 0x11668, 0x11669, 0x1166a, 0x1166b, 0x1166c, 0x1173c, 0x1173d, 0x1173e, 0x11c41, 0x11c42, 0x11c43, 0x11c44, 0x11c45, 0x11c70, 0x11c71, 0x12470, - 0x12471, 0x12472, 0x12473, 0x12474, 0x16a6e, 0x16a6f, 0x16af5, 0x16b37, 0x16b38, 0x16b39, 0x16b3a, 0x16b3b, 0x16b44, 0x1bc9f, 0x1da87, 0x1da88, - 0x1da89, 0x1da8a, 0x1da8b, 0x1e95e, 0x1e95f +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode "Pc", "Pd", "Pe", "Pf", "Pi", "Po", "Ps" categories. + * (generated by scripts/build_punct_map.py) */ + static const unsigned PUNCT_MAP[] = { + R(0x0021,0x0023), R(0x0025,0x002a), R(0x002c,0x002f), R(0x003a,0x003b), R(0x003f,0x0040), + R(0x005b,0x005d), S(0x005f), S(0x007b), S(0x007d), S(0x00a1), S(0x00a7), S(0x00ab), R(0x00b6,0x00b7), + S(0x00bb), S(0x00bf), S(0x037e), S(0x0387), R(0x055a,0x055f), R(0x0589,0x058a), S(0x05be), S(0x05c0), + S(0x05c3), S(0x05c6), R(0x05f3,0x05f4), R(0x0609,0x060a), R(0x060c,0x060d), S(0x061b), R(0x061e,0x061f), + R(0x066a,0x066d), S(0x06d4), R(0x0700,0x070d), R(0x07f7,0x07f9), R(0x0830,0x083e), S(0x085e), + R(0x0964,0x0965), S(0x0970), S(0x09fd), S(0x0a76), S(0x0af0), S(0x0c77), S(0x0c84), S(0x0df4), S(0x0e4f), + R(0x0e5a,0x0e5b), R(0x0f04,0x0f12), S(0x0f14), R(0x0f3a,0x0f3d), S(0x0f85), R(0x0fd0,0x0fd4), + R(0x0fd9,0x0fda), R(0x104a,0x104f), S(0x10fb), R(0x1360,0x1368), S(0x1400), S(0x166e), R(0x169b,0x169c), + R(0x16eb,0x16ed), R(0x1735,0x1736), R(0x17d4,0x17d6), R(0x17d8,0x17da), R(0x1800,0x180a), + R(0x1944,0x1945), R(0x1a1e,0x1a1f), R(0x1aa0,0x1aa6), R(0x1aa8,0x1aad), R(0x1b5a,0x1b60), + R(0x1bfc,0x1bff), R(0x1c3b,0x1c3f), R(0x1c7e,0x1c7f), R(0x1cc0,0x1cc7), S(0x1cd3), R(0x2010,0x2027), + R(0x2030,0x2043), R(0x2045,0x2051), R(0x2053,0x205e), R(0x207d,0x207e), R(0x208d,0x208e), + R(0x2308,0x230b), R(0x2329,0x232a), R(0x2768,0x2775), R(0x27c5,0x27c6), R(0x27e6,0x27ef), + R(0x2983,0x2998), R(0x29d8,0x29db), R(0x29fc,0x29fd), R(0x2cf9,0x2cfc), R(0x2cfe,0x2cff), S(0x2d70), + R(0x2e00,0x2e2e), R(0x2e30,0x2e4f), R(0x3001,0x3003), R(0x3008,0x3011), R(0x3014,0x301f), S(0x3030), + S(0x303d), S(0x30a0), S(0x30fb), R(0xa4fe,0xa4ff), R(0xa60d,0xa60f), S(0xa673), S(0xa67e), + R(0xa6f2,0xa6f7), R(0xa874,0xa877), R(0xa8ce,0xa8cf), R(0xa8f8,0xa8fa), S(0xa8fc), R(0xa92e,0xa92f), + S(0xa95f), R(0xa9c1,0xa9cd), R(0xa9de,0xa9df), R(0xaa5c,0xaa5f), R(0xaade,0xaadf), R(0xaaf0,0xaaf1), + S(0xabeb), R(0xfd3e,0xfd3f), R(0xfe10,0xfe19), R(0xfe30,0xfe52), R(0xfe54,0xfe61), S(0xfe63), S(0xfe68), + R(0xfe6a,0xfe6b), R(0xff01,0xff03), R(0xff05,0xff0a), R(0xff0c,0xff0f), R(0xff1a,0xff1b), + R(0xff1f,0xff20), R(0xff3b,0xff3d), S(0xff3f), S(0xff5b), S(0xff5d), R(0xff5f,0xff65), R(0x10100,0x10102), + S(0x1039f), S(0x103d0), S(0x1056f), S(0x10857), S(0x1091f), S(0x1093f), R(0x10a50,0x10a58), S(0x10a7f), + R(0x10af0,0x10af6), R(0x10b39,0x10b3f), R(0x10b99,0x10b9c), R(0x10f55,0x10f59), R(0x11047,0x1104d), + R(0x110bb,0x110bc), R(0x110be,0x110c1), R(0x11140,0x11143), R(0x11174,0x11175), R(0x111c5,0x111c8), + S(0x111cd), S(0x111db), R(0x111dd,0x111df), R(0x11238,0x1123d), S(0x112a9), R(0x1144b,0x1144f), + S(0x1145b), S(0x1145d), S(0x114c6), R(0x115c1,0x115d7), R(0x11641,0x11643), R(0x11660,0x1166c), + R(0x1173c,0x1173e), S(0x1183b), S(0x119e2), R(0x11a3f,0x11a46), R(0x11a9a,0x11a9c), R(0x11a9e,0x11aa2), + R(0x11c41,0x11c45), R(0x11c70,0x11c71), R(0x11ef7,0x11ef8), S(0x11fff), R(0x12470,0x12474), + R(0x16a6e,0x16a6f), S(0x16af5), R(0x16b37,0x16b3b), S(0x16b44), R(0x16e97,0x16e9a), S(0x16fe2), + S(0x1bc9f), R(0x1da87,0x1da8b), R(0x1e95e,0x1e95f) }; +#undef R +#undef S - /* The ASCII ones are the most frequently used ones, so lets check them first. */ + /* The ASCII ones are the most frequently used ones, also CommonMark + * specification requests few more in this range. */ if(codepoint <= 0x7f) return ISPUNCT_(codepoint); - return (bsearch(&codepoint, punct_list, SIZEOF_ARRAY(punct_list), sizeof(int), md_unicode_cmp__) != NULL); + return (md_unicode_bsearch__(codepoint, PUNCT_MAP, SIZEOF_ARRAY(PUNCT_MAP)) >= 0); } static void - md_get_unicode_fold_info(int codepoint, MD_UNICODE_FOLD_INFO* info) + md_get_unicode_fold_info(unsigned codepoint, MD_UNICODE_FOLD_INFO* info) { - /* This maps single codepoint within a range to a single codepoint - * within an offseted range. */ - static const struct { - int min_codepoint; - int max_codepoint; - int offset; - } range_map[] = { - { 0x00c0, 0x00d6, 32 }, { 0x00d8, 0x00de, 32 }, { 0x0388, 0x038a, 37 }, { 0x0391, 0x03a1, 32 }, { 0x03a3, 0x03ab, 32 }, { 0x0400, 0x040f, 80 }, - { 0x0410, 0x042f, 32 }, { 0x0531, 0x0556, 48 }, { 0x1f08, 0x1f0f, -8 }, { 0x1f18, 0x1f1d, -8 }, { 0x1f28, 0x1f2f, -8 }, { 0x1f38, 0x1f3f, -8 }, - { 0x1f48, 0x1f4d, -8 }, { 0x1f68, 0x1f6f, -8 }, { 0x1fc8, 0x1fcb, -86 }, { 0x2160, 0x216f, 16 }, { 0x24b6, 0x24cf, 26 }, { 0xff21, 0xff3a, 32 }, - { 0x10400, 0x10425, 40 } +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode "Pc", "Pd", "Pe", "Pf", "Pi", "Po", "Ps" categories. + * (generated by scripts/build_punct_map.py) */ + static const unsigned FOLD_MAP_1[] = { + R(0x0041,0x005a), S(0x00b5), R(0x00c0,0x00d6), R(0x00d8,0x00de), R(0x0100,0x012e), R(0x0132,0x0136), + R(0x0139,0x0147), R(0x014a,0x0176), S(0x0178), R(0x0179,0x017d), S(0x017f), S(0x0181), S(0x0182), + S(0x0186), S(0x0187), S(0x0189), S(0x018b), S(0x018e), S(0x018f), S(0x0190), S(0x0191), S(0x0193), + S(0x0194), S(0x0196), S(0x0197), S(0x0198), S(0x019c), S(0x019d), S(0x019f), R(0x01a0,0x01a4), S(0x01a6), + S(0x01a7), S(0x01a9), S(0x01ac), S(0x01ae), S(0x01af), S(0x01b1), S(0x01b3), S(0x01b7), S(0x01b8), + S(0x01bc), S(0x01c4), S(0x01c5), S(0x01c7), S(0x01c8), S(0x01ca), R(0x01cb,0x01db), R(0x01de,0x01ee), + S(0x01f1), S(0x01f2), S(0x01f6), S(0x01f7), R(0x01f8,0x021e), S(0x0220), R(0x0222,0x0232), S(0x023a), + S(0x023b), S(0x023d), S(0x023e), S(0x0241), S(0x0243), S(0x0244), S(0x0245), R(0x0246,0x024e), S(0x0345), + S(0x0370), S(0x0376), S(0x037f), S(0x0386), R(0x0388,0x038a), S(0x038c), S(0x038e), R(0x0391,0x03a1), + R(0x03a3,0x03ab), S(0x03c2), S(0x03cf), S(0x03d0), S(0x03d1), S(0x03d5), S(0x03d6), R(0x03d8,0x03ee), + S(0x03f0), S(0x03f1), S(0x03f4), S(0x03f5), S(0x03f7), S(0x03f9), S(0x03fa), R(0x03fd,0x03ff), + R(0x0400,0x040f), R(0x0410,0x042f), R(0x0460,0x0480), R(0x048a,0x04be), S(0x04c0), R(0x04c1,0x04cd), + R(0x04d0,0x052e), R(0x0531,0x0556), R(0x10a0,0x10c5), S(0x10c7), S(0x10cd), R(0x13f8,0x13fd), S(0x1c80), + S(0x1c81), S(0x1c82), S(0x1c83), S(0x1c85), S(0x1c86), S(0x1c87), S(0x1c88), R(0x1c90,0x1cba), + R(0x1cbd,0x1cbf), R(0x1e00,0x1e94), S(0x1e9b), R(0x1ea0,0x1efe), R(0x1f08,0x1f0f), R(0x1f18,0x1f1d), + R(0x1f28,0x1f2f), R(0x1f38,0x1f3f), R(0x1f48,0x1f4d), S(0x1f59), S(0x1f5b), S(0x1f5d), S(0x1f5f), + R(0x1f68,0x1f6f), S(0x1fb8), S(0x1fba), S(0x1fbe), R(0x1fc8,0x1fcb), S(0x1fd8), S(0x1fda), S(0x1fe8), + S(0x1fea), S(0x1fec), S(0x1ff8), S(0x1ffa), S(0x2126), S(0x212a), S(0x212b), S(0x2132), R(0x2160,0x216f), + S(0x2183), R(0x24b6,0x24cf), R(0x2c00,0x2c2e), S(0x2c60), S(0x2c62), S(0x2c63), S(0x2c64), + R(0x2c67,0x2c6b), S(0x2c6d), S(0x2c6e), S(0x2c6f), S(0x2c70), S(0x2c72), S(0x2c75), S(0x2c7e), + R(0x2c80,0x2ce2), S(0x2ceb), S(0x2cf2), R(0xa640,0xa66c), R(0xa680,0xa69a), R(0xa722,0xa72e), + R(0xa732,0xa76e), S(0xa779), S(0xa77d), R(0xa77e,0xa786), S(0xa78b), S(0xa78d), S(0xa790), + R(0xa796,0xa7a8), S(0xa7aa), S(0xa7ab), S(0xa7ac), S(0xa7ad), S(0xa7ae), S(0xa7b0), S(0xa7b1), S(0xa7b2), + S(0xa7b3), R(0xa7b4,0xa7be), S(0xa7c2), S(0xa7c4), S(0xa7c5), S(0xa7c6), R(0xab70,0xabbf), + R(0xff21,0xff3a), R(0x10400,0x10427), R(0x104b0,0x104d3), R(0x10c80,0x10cb2), R(0x118a0,0x118bf), + R(0x16e40,0x16e5f), R(0x1e900,0x1e921) }; - - /* This maps single codepoint to another single codepoint. */ - static const struct { - int src_codepoint; - int dest_codepoint; - } single_map[] = { - { 0x00b5, 0x03bc }, { 0x0100, 0x0101 }, { 0x0102, 0x0103 }, { 0x0104, 0x0105 }, { 0x0106, 0x0107 }, { 0x0108, 0x0109 }, { 0x010a, 0x010b }, { 0x010c, 0x010d }, - { 0x010e, 0x010f }, { 0x0110, 0x0111 }, { 0x0112, 0x0113 }, { 0x0114, 0x0115 }, { 0x0116, 0x0117 }, { 0x0118, 0x0119 }, { 0x011a, 0x011b }, { 0x011c, 0x011d }, - { 0x011e, 0x011f }, { 0x0120, 0x0121 }, { 0x0122, 0x0123 }, { 0x0124, 0x0125 }, { 0x0126, 0x0127 }, { 0x0128, 0x0129 }, { 0x012a, 0x012b }, { 0x012c, 0x012d }, - { 0x012e, 0x012f }, { 0x0132, 0x0133 }, { 0x0134, 0x0135 }, { 0x0136, 0x0137 }, { 0x0139, 0x013a }, { 0x013b, 0x013c }, { 0x013d, 0x013e }, { 0x013f, 0x0140 }, - { 0x0141, 0x0142 }, { 0x0143, 0x0144 }, { 0x0145, 0x0146 }, { 0x0147, 0x0148 }, { 0x014a, 0x014b }, { 0x014c, 0x014d }, { 0x014e, 0x014f }, { 0x0150, 0x0151 }, - { 0x0152, 0x0153 }, { 0x0154, 0x0155 }, { 0x0156, 0x0157 }, { 0x0158, 0x0159 }, { 0x015a, 0x015b }, { 0x015c, 0x015d }, { 0x015e, 0x015f }, { 0x0160, 0x0161 }, - { 0x0162, 0x0163 }, { 0x0164, 0x0165 }, { 0x0166, 0x0167 }, { 0x0168, 0x0169 }, { 0x016a, 0x016b }, { 0x016c, 0x016d }, { 0x016e, 0x016f }, { 0x0170, 0x0171 }, - { 0x0172, 0x0173 }, { 0x0174, 0x0175 }, { 0x0176, 0x0177 }, { 0x0178, 0x00ff }, { 0x0179, 0x017a }, { 0x017b, 0x017c }, { 0x017d, 0x017e }, { 0x017f, 0x0073 }, - { 0x0181, 0x0253 }, { 0x0182, 0x0183 }, { 0x0184, 0x0185 }, { 0x0186, 0x0254 }, { 0x0187, 0x0188 }, { 0x0189, 0x0256 }, { 0x018a, 0x0257 }, { 0x018b, 0x018c }, - { 0x018e, 0x01dd }, { 0x018f, 0x0259 }, { 0x0190, 0x025b }, { 0x0191, 0x0192 }, { 0x0193, 0x0260 }, { 0x0194, 0x0263 }, { 0x0196, 0x0269 }, { 0x0197, 0x0268 }, - { 0x0198, 0x0199 }, { 0x019c, 0x026f }, { 0x019d, 0x0272 }, { 0x019f, 0x0275 }, { 0x01a0, 0x01a1 }, { 0x01a2, 0x01a3 }, { 0x01a4, 0x01a5 }, { 0x01a6, 0x0280 }, - { 0x01a7, 0x01a8 }, { 0x01a9, 0x0283 }, { 0x01ac, 0x01ad }, { 0x01ae, 0x0288 }, { 0x01af, 0x01b0 }, { 0x01b1, 0x028a }, { 0x01b2, 0x028b }, { 0x01b3, 0x01b4 }, - { 0x01b5, 0x01b6 }, { 0x01b7, 0x0292 }, { 0x01b8, 0x01b9 }, { 0x01bc, 0x01bd }, { 0x01c4, 0x01c6 }, { 0x01c5, 0x01c6 }, { 0x01c7, 0x01c9 }, { 0x01c8, 0x01c9 }, - { 0x01ca, 0x01cc }, { 0x01cb, 0x01cc }, { 0x01cd, 0x01ce }, { 0x01cf, 0x01d0 }, { 0x01d1, 0x01d2 }, { 0x01d3, 0x01d4 }, { 0x01d5, 0x01d6 }, { 0x01d7, 0x01d8 }, - { 0x01d9, 0x01da }, { 0x01db, 0x01dc }, { 0x01de, 0x01df }, { 0x01e0, 0x01e1 }, { 0x01e2, 0x01e3 }, { 0x01e4, 0x01e5 }, { 0x01e6, 0x01e7 }, { 0x01e8, 0x01e9 }, - { 0x01ea, 0x01eb }, { 0x01ec, 0x01ed }, { 0x01ee, 0x01ef }, { 0x01f1, 0x01f3 }, { 0x01f2, 0x01f3 }, { 0x01f4, 0x01f5 }, { 0x01f6, 0x0195 }, { 0x01f7, 0x01bf }, - { 0x01f8, 0x01f9 }, { 0x01fa, 0x01fb }, { 0x01fc, 0x01fd }, { 0x01fe, 0x01ff }, { 0x0200, 0x0201 }, { 0x0202, 0x0203 }, { 0x0204, 0x0205 }, { 0x0206, 0x0207 }, - { 0x0208, 0x0209 }, { 0x020a, 0x020b }, { 0x020c, 0x020d }, { 0x020e, 0x020f }, { 0x0210, 0x0211 }, { 0x0212, 0x0213 }, { 0x0214, 0x0215 }, { 0x0216, 0x0217 }, - { 0x0218, 0x0219 }, { 0x021a, 0x021b }, { 0x021c, 0x021d }, { 0x021e, 0x021f }, { 0x0220, 0x019e }, { 0x0222, 0x0223 }, { 0x0224, 0x0225 }, { 0x0226, 0x0227 }, - { 0x0228, 0x0229 }, { 0x022a, 0x022b }, { 0x022c, 0x022d }, { 0x022e, 0x022f }, { 0x0230, 0x0231 }, { 0x0232, 0x0233 }, { 0x0345, 0x03b9 }, { 0x0386, 0x03ac }, - { 0x038c, 0x03cc }, { 0x038e, 0x03cd }, { 0x038f, 0x03ce }, { 0x03c2, 0x03c3 }, { 0x03d0, 0x03b2 }, { 0x03d1, 0x03b8 }, { 0x03d5, 0x03c6 }, { 0x03d6, 0x03c0 }, - { 0x03d8, 0x03d9 }, { 0x03da, 0x03db }, { 0x03dc, 0x03dd }, { 0x03de, 0x03df }, { 0x03e0, 0x03e1 }, { 0x03e2, 0x03e3 }, { 0x03e4, 0x03e5 }, { 0x03e6, 0x03e7 }, - { 0x03e8, 0x03e9 }, { 0x03ea, 0x03eb }, { 0x03ec, 0x03ed }, { 0x03ee, 0x03ef }, { 0x03f0, 0x03ba }, { 0x03f1, 0x03c1 }, { 0x03f2, 0x03c3 }, { 0x03f4, 0x03b8 }, - { 0x03f5, 0x03b5 }, { 0x0460, 0x0461 }, { 0x0462, 0x0463 }, { 0x0464, 0x0465 }, { 0x0466, 0x0467 }, { 0x0468, 0x0469 }, { 0x046a, 0x046b }, { 0x046c, 0x046d }, - { 0x046e, 0x046f }, { 0x0470, 0x0471 }, { 0x0472, 0x0473 }, { 0x0474, 0x0475 }, { 0x0476, 0x0477 }, { 0x0478, 0x0479 }, { 0x047a, 0x047b }, { 0x047c, 0x047d }, - { 0x047e, 0x047f }, { 0x0480, 0x0481 }, { 0x048a, 0x048b }, { 0x048c, 0x048d }, { 0x048e, 0x048f }, { 0x0490, 0x0491 }, { 0x0492, 0x0493 }, { 0x0494, 0x0495 }, - { 0x0496, 0x0497 }, { 0x0498, 0x0499 }, { 0x049a, 0x049b }, { 0x049c, 0x049d }, { 0x049e, 0x049f }, { 0x04a0, 0x04a1 }, { 0x04a2, 0x04a3 }, { 0x04a4, 0x04a5 }, - { 0x04a6, 0x04a7 }, { 0x04a8, 0x04a9 }, { 0x04aa, 0x04ab }, { 0x04ac, 0x04ad }, { 0x04ae, 0x04af }, { 0x04b0, 0x04b1 }, { 0x04b2, 0x04b3 }, { 0x04b4, 0x04b5 }, - { 0x04b6, 0x04b7 }, { 0x04b8, 0x04b9 }, { 0x04ba, 0x04bb }, { 0x04bc, 0x04bd }, { 0x04be, 0x04bf }, { 0x04c1, 0x04c2 }, { 0x04c3, 0x04c4 }, { 0x04c5, 0x04c6 }, - { 0x04c7, 0x04c8 }, { 0x04c9, 0x04ca }, { 0x04cb, 0x04cc }, { 0x04cd, 0x04ce }, { 0x04d0, 0x04d1 }, { 0x04d2, 0x04d3 }, { 0x04d4, 0x04d5 }, { 0x04d6, 0x04d7 }, - { 0x04d8, 0x04d9 }, { 0x04da, 0x04db }, { 0x04dc, 0x04dd }, { 0x04de, 0x04df }, { 0x04e0, 0x04e1 }, { 0x04e2, 0x04e3 }, { 0x04e4, 0x04e5 }, { 0x04e6, 0x04e7 }, - { 0x04e8, 0x04e9 }, { 0x04ea, 0x04eb }, { 0x04ec, 0x04ed }, { 0x04ee, 0x04ef }, { 0x04f0, 0x04f1 }, { 0x04f2, 0x04f3 }, { 0x04f4, 0x04f5 }, { 0x04f8, 0x04f9 }, - { 0x0500, 0x0501 }, { 0x0502, 0x0503 }, { 0x0504, 0x0505 }, { 0x0506, 0x0507 }, { 0x0508, 0x0509 }, { 0x050a, 0x050b }, { 0x050c, 0x050d }, { 0x050e, 0x050f }, - { 0x1e00, 0x1e01 }, { 0x1e02, 0x1e03 }, { 0x1e04, 0x1e05 }, { 0x1e06, 0x1e07 }, { 0x1e08, 0x1e09 }, { 0x1e0a, 0x1e0b }, { 0x1e0c, 0x1e0d }, { 0x1e0e, 0x1e0f }, - { 0x1e10, 0x1e11 }, { 0x1e12, 0x1e13 }, { 0x1e14, 0x1e15 }, { 0x1e16, 0x1e17 }, { 0x1e18, 0x1e19 }, { 0x1e1a, 0x1e1b }, { 0x1e1c, 0x1e1d }, { 0x1e1e, 0x1e1f }, - { 0x1e20, 0x1e21 }, { 0x1e22, 0x1e23 }, { 0x1e24, 0x1e25 }, { 0x1e26, 0x1e27 }, { 0x1e28, 0x1e29 }, { 0x1e2a, 0x1e2b }, { 0x1e2c, 0x1e2d }, { 0x1e2e, 0x1e2f }, - { 0x1e30, 0x1e31 }, { 0x1e32, 0x1e33 }, { 0x1e34, 0x1e35 }, { 0x1e36, 0x1e37 }, { 0x1e38, 0x1e39 }, { 0x1e3a, 0x1e3b }, { 0x1e3c, 0x1e3d }, { 0x1e3e, 0x1e3f }, - { 0x1e40, 0x1e41 }, { 0x1e42, 0x1e43 }, { 0x1e44, 0x1e45 }, { 0x1e46, 0x1e47 }, { 0x1e48, 0x1e49 }, { 0x1e4a, 0x1e4b }, { 0x1e4c, 0x1e4d }, { 0x1e4e, 0x1e4f }, - { 0x1e50, 0x1e51 }, { 0x1e52, 0x1e53 }, { 0x1e54, 0x1e55 }, { 0x1e56, 0x1e57 }, { 0x1e58, 0x1e59 }, { 0x1e5a, 0x1e5b }, { 0x1e5c, 0x1e5d }, { 0x1e5e, 0x1e5f }, - { 0x1e60, 0x1e61 }, { 0x1e62, 0x1e63 }, { 0x1e64, 0x1e65 }, { 0x1e66, 0x1e67 }, { 0x1e68, 0x1e69 }, { 0x1e6a, 0x1e6b }, { 0x1e6c, 0x1e6d }, { 0x1e6e, 0x1e6f }, - { 0x1e70, 0x1e71 }, { 0x1e72, 0x1e73 }, { 0x1e74, 0x1e75 }, { 0x1e76, 0x1e77 }, { 0x1e78, 0x1e79 }, { 0x1e7a, 0x1e7b }, { 0x1e7c, 0x1e7d }, { 0x1e7e, 0x1e7f }, - { 0x1e80, 0x1e81 }, { 0x1e82, 0x1e83 }, { 0x1e84, 0x1e85 }, { 0x1e86, 0x1e87 }, { 0x1e88, 0x1e89 }, { 0x1e8a, 0x1e8b }, { 0x1e8c, 0x1e8d }, { 0x1e8e, 0x1e8f }, - { 0x1e90, 0x1e91 }, { 0x1e92, 0x1e93 }, { 0x1e94, 0x1e95 }, { 0x1e9b, 0x1e61 }, { 0x1ea0, 0x1ea1 }, { 0x1ea2, 0x1ea3 }, { 0x1ea4, 0x1ea5 }, { 0x1ea6, 0x1ea7 }, - { 0x1ea8, 0x1ea9 }, { 0x1eaa, 0x1eab }, { 0x1eac, 0x1ead }, { 0x1eae, 0x1eaf }, { 0x1eb0, 0x1eb1 }, { 0x1eb2, 0x1eb3 }, { 0x1eb4, 0x1eb5 }, { 0x1eb6, 0x1eb7 }, - { 0x1eb8, 0x1eb9 }, { 0x1eba, 0x1ebb }, { 0x1ebc, 0x1ebd }, { 0x1ebe, 0x1ebf }, { 0x1ec0, 0x1ec1 }, { 0x1ec2, 0x1ec3 }, { 0x1ec4, 0x1ec5 }, { 0x1ec6, 0x1ec7 }, - { 0x1ec8, 0x1ec9 }, { 0x1eca, 0x1ecb }, { 0x1ecc, 0x1ecd }, { 0x1ece, 0x1ecf }, { 0x1ed0, 0x1ed1 }, { 0x1ed2, 0x1ed3 }, { 0x1ed4, 0x1ed5 }, { 0x1ed6, 0x1ed7 }, - { 0x1ed8, 0x1ed9 }, { 0x1eda, 0x1edb }, { 0x1edc, 0x1edd }, { 0x1ede, 0x1edf }, { 0x1ee0, 0x1ee1 }, { 0x1ee2, 0x1ee3 }, { 0x1ee4, 0x1ee5 }, { 0x1ee6, 0x1ee7 }, - { 0x1ee8, 0x1ee9 }, { 0x1eea, 0x1eeb }, { 0x1eec, 0x1eed }, { 0x1eee, 0x1eef }, { 0x1ef0, 0x1ef1 }, { 0x1ef2, 0x1ef3 }, { 0x1ef4, 0x1ef5 }, { 0x1ef6, 0x1ef7 }, - { 0x1ef8, 0x1ef9 }, { 0x1f59, 0x1f51 }, { 0x1f5b, 0x1f53 }, { 0x1f5d, 0x1f55 }, { 0x1f5f, 0x1f57 }, { 0x1fb8, 0x1fb0 }, { 0x1fb9, 0x1fb1 }, { 0x1fba, 0x1f70 }, - { 0x1fbb, 0x1f71 }, { 0x1fbe, 0x03b9 }, { 0x1fd8, 0x1fd0 }, { 0x1fd9, 0x1fd1 }, { 0x1fda, 0x1f76 }, { 0x1fdb, 0x1f77 }, { 0x1fe8, 0x1fe0 }, { 0x1fe9, 0x1fe1 }, - { 0x1fea, 0x1f7a }, { 0x1feb, 0x1f7b }, { 0x1fec, 0x1fe5 }, { 0x1ff8, 0x1f78 }, { 0x1ff9, 0x1f79 }, { 0x1ffa, 0x1f7c }, { 0x1ffb, 0x1f7d }, { 0x2126, 0x03c9 }, - { 0x212a, 0x006b }, { 0x212b, 0x00e5 }, + static const unsigned FOLD_MAP_1_DATA[] = { + 0x0061, 0x007a, 0x03bc, 0x00e0, 0x00f6, 0x00f8, 0x00fe, 0x0101, 0x012f, 0x0133, 0x0137, 0x013a, 0x0148, + 0x014b, 0x0177, 0x00ff, 0x017a, 0x017e, 0x0073, 0x0253, 0x0183, 0x0254, 0x0188, 0x0256, 0x018c, 0x01dd, + 0x0259, 0x025b, 0x0192, 0x0260, 0x0263, 0x0269, 0x0268, 0x0199, 0x026f, 0x0272, 0x0275, 0x01a1, 0x01a5, + 0x0280, 0x01a8, 0x0283, 0x01ad, 0x0288, 0x01b0, 0x028a, 0x01b4, 0x0292, 0x01b9, 0x01bd, 0x01c6, 0x01c6, + 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01dc, 0x01df, 0x01ef, 0x01f3, 0x01f3, 0x0195, 0x01bf, 0x01f9, 0x021f, + 0x019e, 0x0223, 0x0233, 0x2c65, 0x023c, 0x019a, 0x2c66, 0x0242, 0x0180, 0x0289, 0x028c, 0x0247, 0x024f, + 0x03b9, 0x0371, 0x0377, 0x03f3, 0x03ac, 0x03ad, 0x03af, 0x03cc, 0x03cd, 0x03b1, 0x03c1, 0x03c3, 0x03cb, + 0x03c3, 0x03d7, 0x03b2, 0x03b8, 0x03c6, 0x03c0, 0x03d9, 0x03ef, 0x03ba, 0x03c1, 0x03b8, 0x03b5, 0x03f8, + 0x03f2, 0x03fb, 0x037b, 0x037d, 0x0450, 0x045f, 0x0430, 0x044f, 0x0461, 0x0481, 0x048b, 0x04bf, 0x04cf, + 0x04c2, 0x04ce, 0x04d1, 0x052f, 0x0561, 0x0586, 0x2d00, 0x2d25, 0x2d27, 0x2d2d, 0x13f0, 0x13f5, 0x0432, + 0x0434, 0x043e, 0x0441, 0x0442, 0x044a, 0x0463, 0xa64b, 0x10d0, 0x10fa, 0x10fd, 0x10ff, 0x1e01, 0x1e95, + 0x1e61, 0x1ea1, 0x1eff, 0x1f00, 0x1f07, 0x1f10, 0x1f15, 0x1f20, 0x1f27, 0x1f30, 0x1f37, 0x1f40, 0x1f45, + 0x1f51, 0x1f53, 0x1f55, 0x1f57, 0x1f60, 0x1f67, 0x1fb0, 0x1f70, 0x03b9, 0x1f72, 0x1f75, 0x1fd0, 0x1f76, + 0x1fe0, 0x1f7a, 0x1fe5, 0x1f78, 0x1f7c, 0x03c9, 0x006b, 0x00e5, 0x214e, 0x2170, 0x217f, 0x2184, 0x24d0, + 0x24e9, 0x2c30, 0x2c5e, 0x2c61, 0x026b, 0x1d7d, 0x027d, 0x2c68, 0x2c6c, 0x0251, 0x0271, 0x0250, 0x0252, + 0x2c73, 0x2c76, 0x023f, 0x2c81, 0x2ce3, 0x2cec, 0x2cf3, 0xa641, 0xa66d, 0xa681, 0xa69b, 0xa723, 0xa72f, + 0xa733, 0xa76f, 0xa77a, 0x1d79, 0xa77f, 0xa787, 0xa78c, 0x0265, 0xa791, 0xa797, 0xa7a9, 0x0266, 0x025c, + 0x0261, 0x026c, 0x026a, 0x029e, 0x0287, 0x029d, 0xab53, 0xa7b5, 0xa7bf, 0xa7c3, 0xa794, 0x0282, 0x1d8e, + 0x13a0, 0x13ef, 0xff41, 0xff5a, 0x10428, 0x1044f, 0x104d8, 0x104fb, 0x10cc0, 0x10cf2, 0x118c0, 0x118df, + 0x16e60, 0x16e7f, 0x1e922, 0x1e943 }; - - /* This maps single codepoint to two codepoints. */ - static const struct { - int src_codepoint; - int dest_codepoint0; - int dest_codepoint1; - } double_map[] = { - { 0x00df, 0x0073, 0x0073 }, { 0x0130, 0x0069, 0x0307 }, { 0x0149, 0x02bc, 0x006e }, { 0x01f0, 0x006a, 0x030c }, { 0x0587, 0x0565, 0x0582 }, { 0x1e96, 0x0068, 0x0331 }, - { 0x1e97, 0x0074, 0x0308 }, { 0x1e98, 0x0077, 0x030a }, { 0x1e99, 0x0079, 0x030a }, { 0x1e9a, 0x0061, 0x02be }, { 0x1f50, 0x03c5, 0x0313 }, { 0x1f80, 0x1f00, 0x03b9 }, - { 0x1f81, 0x1f01, 0x03b9 }, { 0x1f82, 0x1f02, 0x03b9 }, { 0x1f83, 0x1f03, 0x03b9 }, { 0x1f84, 0x1f04, 0x03b9 }, { 0x1f85, 0x1f05, 0x03b9 }, { 0x1f86, 0x1f06, 0x03b9 }, - { 0x1f87, 0x1f07, 0x03b9 }, { 0x1f88, 0x1f00, 0x03b9 }, { 0x1f89, 0x1f01, 0x03b9 }, { 0x1f8a, 0x1f02, 0x03b9 }, { 0x1f8b, 0x1f03, 0x03b9 }, { 0x1f8c, 0x1f04, 0x03b9 }, - { 0x1f8d, 0x1f05, 0x03b9 }, { 0x1f8e, 0x1f06, 0x03b9 }, { 0x1f8f, 0x1f07, 0x03b9 }, { 0x1f90, 0x1f20, 0x03b9 }, { 0x1f91, 0x1f21, 0x03b9 }, { 0x1f92, 0x1f22, 0x03b9 }, - { 0x1f93, 0x1f23, 0x03b9 }, { 0x1f94, 0x1f24, 0x03b9 }, { 0x1f95, 0x1f25, 0x03b9 }, { 0x1f96, 0x1f26, 0x03b9 }, { 0x1f97, 0x1f27, 0x03b9 }, { 0x1f98, 0x1f20, 0x03b9 }, - { 0x1f99, 0x1f21, 0x03b9 }, { 0x1f9a, 0x1f22, 0x03b9 }, { 0x1f9b, 0x1f23, 0x03b9 }, { 0x1f9c, 0x1f24, 0x03b9 }, { 0x1f9d, 0x1f25, 0x03b9 }, { 0x1f9e, 0x1f26, 0x03b9 }, - { 0x1f9f, 0x1f27, 0x03b9 }, { 0x1fa0, 0x1f60, 0x03b9 }, { 0x1fa1, 0x1f61, 0x03b9 }, { 0x1fa2, 0x1f62, 0x03b9 }, { 0x1fa3, 0x1f63, 0x03b9 }, { 0x1fa4, 0x1f64, 0x03b9 }, - { 0x1fa5, 0x1f65, 0x03b9 }, { 0x1fa6, 0x1f66, 0x03b9 }, { 0x1fa7, 0x1f67, 0x03b9 }, { 0x1fa8, 0x1f60, 0x03b9 }, { 0x1fa9, 0x1f61, 0x03b9 }, { 0x1faa, 0x1f62, 0x03b9 }, - { 0x1fab, 0x1f63, 0x03b9 }, { 0x1fac, 0x1f64, 0x03b9 }, { 0x1fad, 0x1f65, 0x03b9 }, { 0x1fae, 0x1f66, 0x03b9 }, { 0x1faf, 0x1f67, 0x03b9 }, { 0x1fb2, 0x1f70, 0x03b9 }, - { 0x1fb3, 0x03b1, 0x03b9 }, { 0x1fb4, 0x03ac, 0x03b9 }, { 0x1fb6, 0x03b1, 0x0342 }, { 0x1fbc, 0x03b1, 0x03b9 }, { 0x1fc2, 0x1f74, 0x03b9 }, { 0x1fc3, 0x03b7, 0x03b9 }, - { 0x1fc4, 0x03ae, 0x03b9 }, { 0x1fc6, 0x03b7, 0x0342 }, { 0x1fcc, 0x03b7, 0x03b9 }, { 0x1fd6, 0x03b9, 0x0342 }, { 0x1fe4, 0x03c1, 0x0313 }, { 0x1fe6, 0x03c5, 0x0342 }, - { 0x1ff2, 0x1f7c, 0x03b9 }, { 0x1ff3, 0x03c9, 0x03b9 }, { 0x1ff4, 0x03ce, 0x03b9 }, { 0x1ff6, 0x03c9, 0x0342 }, { 0x1ffc, 0x03c9, 0x03b9 }, { 0xfb00, 0x0066, 0x0066 }, - { 0xfb01, 0x0066, 0x0069 }, { 0xfb02, 0x0066, 0x006c }, { 0xfb05, 0x0073, 0x0074 }, { 0xfb06, 0x0073, 0x0074 }, { 0xfb13, 0x0574, 0x0576 }, { 0xfb14, 0x0574, 0x0565 }, - { 0xfb15, 0x0574, 0x056b }, { 0xfb16, 0x057e, 0x0576 }, { 0xfb17, 0x0574, 0x056d } + static const unsigned FOLD_MAP_2[] = { + S(0x00df), S(0x0130), S(0x0149), S(0x01f0), S(0x0587), S(0x1e96), S(0x1e97), S(0x1e98), S(0x1e99), + S(0x1e9a), S(0x1e9e), S(0x1f50), R(0x1f80,0x1f87), R(0x1f88,0x1f8f), R(0x1f90,0x1f97), R(0x1f98,0x1f9f), + R(0x1fa0,0x1fa7), R(0x1fa8,0x1faf), S(0x1fb2), S(0x1fb3), S(0x1fb4), S(0x1fb6), S(0x1fbc), S(0x1fc2), + S(0x1fc3), S(0x1fc4), S(0x1fc6), S(0x1fcc), S(0x1fd6), S(0x1fe4), S(0x1fe6), S(0x1ff2), S(0x1ff3), + S(0x1ff4), S(0x1ff6), S(0x1ffc), S(0xfb00), S(0xfb01), S(0xfb02), S(0xfb05), S(0xfb06), S(0xfb13), + S(0xfb14), S(0xfb15), S(0xfb16), S(0xfb17) }; - - /* This maps single codepoint to three codepoints. */ + static const unsigned FOLD_MAP_2_DATA[] = { + 0x0073,0x0073, 0x0069,0x0307, 0x02bc,0x006e, 0x006a,0x030c, 0x0565,0x0582, 0x0068,0x0331, 0x0074,0x0308, + 0x0077,0x030a, 0x0079,0x030a, 0x0061,0x02be, 0x0073,0x0073, 0x03c5,0x0313, 0x1f00,0x03b9, 0x1f07,0x03b9, + 0x1f00,0x03b9, 0x1f07,0x03b9, 0x1f20,0x03b9, 0x1f27,0x03b9, 0x1f20,0x03b9, 0x1f27,0x03b9, 0x1f60,0x03b9, + 0x1f67,0x03b9, 0x1f60,0x03b9, 0x1f67,0x03b9, 0x1f70,0x03b9, 0x03b1,0x03b9, 0x03ac,0x03b9, 0x03b1,0x0342, + 0x03b1,0x03b9, 0x1f74,0x03b9, 0x03b7,0x03b9, 0x03ae,0x03b9, 0x03b7,0x0342, 0x03b7,0x03b9, 0x03b9,0x0342, + 0x03c1,0x0313, 0x03c5,0x0342, 0x1f7c,0x03b9, 0x03c9,0x03b9, 0x03ce,0x03b9, 0x03c9,0x0342, 0x03c9,0x03b9, + 0x0066,0x0066, 0x0066,0x0069, 0x0066,0x006c, 0x0073,0x0074, 0x0073,0x0074, 0x0574,0x0576, 0x0574,0x0565, + 0x0574,0x056b, 0x057e,0x0576, 0x0574,0x056d + }; + static const unsigned FOLD_MAP_3[] = { + S(0x0390), S(0x03b0), S(0x1f52), S(0x1f54), S(0x1f56), S(0x1fb7), S(0x1fc7), S(0x1fd2), S(0x1fd3), + S(0x1fd7), S(0x1fe2), S(0x1fe3), S(0x1fe7), S(0x1ff7), S(0xfb03), S(0xfb04) + }; + static const unsigned FOLD_MAP_3_DATA[] = { + 0x03b9,0x0308,0x0301, 0x03c5,0x0308,0x0301, 0x03c5,0x0313,0x0300, 0x03c5,0x0313,0x0301, + 0x03c5,0x0313,0x0342, 0x03b1,0x0342,0x03b9, 0x03b7,0x0342,0x03b9, 0x03b9,0x0308,0x0300, + 0x03b9,0x0308,0x0301, 0x03b9,0x0308,0x0342, 0x03c5,0x0308,0x0300, 0x03c5,0x0308,0x0301, + 0x03c5,0x0308,0x0342, 0x03c9,0x0342,0x03b9, 0x0066,0x0066,0x0069, 0x0066,0x0066,0x006c + }; +#undef R +#undef S static const struct { - int src_codepoint; - int dest_codepoint0; - int dest_codepoint1; - int dest_codepoint2; - } triple_map[] = { - { 0x0390, 0x03b9, 0x0308, 0x0301 }, { 0x03b0, 0x03c5, 0x0308, 0x0301 }, { 0x1f52, 0x03c5, 0x0313, 0x0300 }, { 0x1f54, 0x03c5, 0x0313, 0x0301 }, - { 0x1f56, 0x03c5, 0x0313, 0x0342 }, { 0x1fb7, 0x03b1, 0x0342, 0x03b9 }, { 0x1fc7, 0x03b7, 0x0342, 0x03b9 }, { 0x1fd2, 0x03b9, 0x0308, 0x0300 }, - { 0x1fd3, 0x03b9, 0x0308, 0x0301 }, { 0x1fd7, 0x03b9, 0x0308, 0x0342 }, { 0x1fe2, 0x03c5, 0x0308, 0x0300 }, { 0x1fe3, 0x03c5, 0x0308, 0x0301 }, - { 0x1fe7, 0x03c5, 0x0308, 0x0342 }, { 0x1ff7, 0x03c9, 0x0342, 0x03b9 }, { 0xfb03, 0x0066, 0x0066, 0x0069 }, { 0xfb04, 0x0066, 0x0066, 0x006c } + const unsigned* map; + const unsigned* data; + size_t map_size; + int n_codepoints; + } FOLD_MAP_LIST[] = { + { FOLD_MAP_1, FOLD_MAP_1_DATA, SIZEOF_ARRAY(FOLD_MAP_1), 1 }, + { FOLD_MAP_2, FOLD_MAP_2_DATA, SIZEOF_ARRAY(FOLD_MAP_2), 2 }, + { FOLD_MAP_3, FOLD_MAP_3_DATA, SIZEOF_ARRAY(FOLD_MAP_3), 3 } }; int i; @@ -661,41 +675,37 @@ struct MD_UNICODE_FOLD_INFO_tag { return; } - for(i = 0; i < SIZEOF_ARRAY(range_map); i++) { - if(range_map[i].min_codepoint <= codepoint && codepoint <= range_map[i].max_codepoint) { - info->codepoints[0] = codepoint + range_map[i].offset; - info->n_codepoints = 1; - return; - } - } - - for(i = 0; i < SIZEOF_ARRAY(single_map); i++) { - if(codepoint == single_map[i].src_codepoint) { - info->codepoints[0] = single_map[i].dest_codepoint; - info->n_codepoints = 1; - return; - } - } - - for(i = 0; i < SIZEOF_ARRAY(double_map); i++) { - if(codepoint == double_map[i].src_codepoint) { - info->codepoints[0] = double_map[i].dest_codepoint0; - info->codepoints[1] = double_map[i].dest_codepoint1; - info->n_codepoints = 2; - return; - } - } + /* Try to locate the codepoint in any of the maps. */ + for(i = 0; i < (int) SIZEOF_ARRAY(FOLD_MAP_LIST); i++) { + int index; + + index = md_unicode_bsearch__(codepoint, FOLD_MAP_LIST[i].map, FOLD_MAP_LIST[i].map_size); + if(index >= 0) { + /* Found the mapping. */ + int n_codepoints = FOLD_MAP_LIST[i].n_codepoints; + const unsigned* map = FOLD_MAP_LIST[i].map; + const unsigned* codepoints = FOLD_MAP_LIST[i].data + (index * n_codepoints); + + memcpy(info->codepoints, codepoints, sizeof(unsigned) * n_codepoints); + info->n_codepoints = n_codepoints; + + if(FOLD_MAP_LIST[i].map[index] != codepoint) { + /* The found mapping maps whole range of codepoints, + * i.e. we have to offset info->codepoints[0] accordingly. */ + if((map[index] & 0x00ffffff)+1 == codepoints[0]) { + /* Alternating type of the range. */ + info->codepoints[0] = codepoint + ((codepoint & 0x1) == (map[index] & 0x1) ? 1 : 0); + } else { + /* Range to range kind of mapping. */ + info->codepoints[0] += (codepoint - (map[index] & 0x00ffffff)); + } + } - for(i = 0; i < SIZEOF_ARRAY(triple_map); i++) { - if(codepoint == triple_map[i].src_codepoint) { - info->codepoints[0] = triple_map[i].dest_codepoint0; - info->codepoints[1] = triple_map[i].dest_codepoint1; - info->codepoints[2] = triple_map[i].dest_codepoint2; - info->n_codepoints = 3; return; } } + /* No mapping found. Map the codepoint to itself. */ info->codepoints[0] = codepoint; info->n_codepoints = 1; } @@ -707,7 +717,7 @@ struct MD_UNICODE_FOLD_INFO_tag { #define IS_UTF16_SURROGATE_LO(word) (((WORD)(word) & 0xfc00) == 0xdc00) #define UTF16_DECODE_SURROGATE(hi, lo) (0x10000 + ((((unsigned)(hi) & 0x3ff) << 10) | (((unsigned)(lo) & 0x3ff) << 0))) - static int + static unsigned md_decode_utf16le__(const CHAR* str, SZ str_size, SZ* p_size) { if(IS_UTF16_SURROGATE_HI(str[0])) { @@ -723,7 +733,7 @@ struct MD_UNICODE_FOLD_INFO_tag { return str[0]; } - static int + static unsigned md_decode_utf16le_before__(MD_CTX* ctx, OFF off) { if(off > 2 && IS_UTF16_SURROGATE_HI(CH(off-2)) && IS_UTF16_SURROGATE_LO(CH(off-1))) @@ -752,7 +762,7 @@ struct MD_UNICODE_FOLD_INFO_tag { #define IS_UTF8_LEAD4(byte) (((unsigned char)(byte) & 0xf8) == 0xf0) #define IS_UTF8_TAIL(byte) (((unsigned char)(byte) & 0xc0) == 0x80) - static int + static unsigned md_decode_utf8__(const CHAR* str, SZ str_size, SZ* p_size) { if(!IS_UTF8_LEAD1(str[0])) { @@ -788,10 +798,10 @@ struct MD_UNICODE_FOLD_INFO_tag { if(p_size != NULL) *p_size = 1; - return str[0]; + return (unsigned) str[0]; } - static int + static unsigned md_decode_utf8_before__(MD_CTX* ctx, OFF off) { if(!IS_UTF8_LEAD1(CH(off-1))) { @@ -811,7 +821,7 @@ struct MD_UNICODE_FOLD_INFO_tag { (((unsigned int)CH(off-1) & 0x3f) << 0); } - return CH(off-1); + return (unsigned) CH(off-1); } #define ISUNICODEWHITESPACE_(codepoint) md_is_unicode_whitespace__(codepoint) @@ -821,7 +831,7 @@ struct MD_UNICODE_FOLD_INFO_tag { #define ISUNICODEPUNCT(off) md_is_unicode_punct__(md_decode_utf8__(STR(off), ctx->size - (off), NULL)) #define ISUNICODEPUNCTBEFORE(off) md_is_unicode_punct__(md_decode_utf8_before__(ctx, off)) - static inline int + static inline unsigned md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_char_size) { return md_decode_utf8__(str+off, str_size-off, p_char_size); @@ -835,7 +845,7 @@ struct MD_UNICODE_FOLD_INFO_tag { #define ISUNICODEPUNCTBEFORE(off) ISPUNCT((off)-1) static inline void - md_get_unicode_fold_info(int codepoint, MD_UNICODE_FOLD_INFO* info) + md_get_unicode_fold_info(unsigned codepoint, MD_UNICODE_FOLD_INFO* info) { info->codepoints[0] = codepoint; if(ISUPPER_(codepoint)) @@ -843,11 +853,11 @@ struct MD_UNICODE_FOLD_INFO_tag { info->n_codepoints = 1; } - static inline int + static inline unsigned md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_size) { *p_size = 1; - return str[off]; + return (unsigned) str[off]; } #endif @@ -921,7 +931,7 @@ static OFF md_skip_unicode_whitespace(const CHAR* label, OFF off, SZ size) { SZ char_size; - int codepoint; + unsigned codepoint; while(off < size) { codepoint = md_decode_unicode(label, off, size, &char_size); @@ -1064,108 +1074,93 @@ done: } static int -md_is_html_comment(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) +md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len, + const MD_LINE* lines, int n_lines, + OFF beg, OFF max_end, OFF* p_end, + OFF* p_scan_horizon) { OFF off = beg; int i = 0; - MD_ASSERT(CH(beg) == _T('<')); - - if(off + 4 >= lines[0].end) - return FALSE; - if(CH(off+1) != _T('!') || CH(off+2) != _T('-') || CH(off+3) != _T('-')) - return FALSE; - off += 4; - - /* ">" and "->" must follow the opening. */ - if(off < lines[0].end && CH(off) == _T('>')) - return FALSE; - if(off+1 < lines[0].end && CH(off) == _T('-') && CH(off+1) == _T('>')) + if(off < *p_scan_horizon && *p_scan_horizon >= max_end - len) { + /* We have already scanned the range up to the max_end so we know + * there is nothing to see. */ return FALSE; + } - while(1) { - while(off + 2 < lines[i].end) { - if(CH(off) == _T('-') && CH(off+1) == _T('-')) { - if(CH(off+2) == _T('>')) { - /* Success. */ - off += 2; - goto done; - } else { - /* "--" is prohibited inside the comment. */ - return FALSE; - } + while(TRUE) { + while(off + len <= lines[i].end && off + len <= max_end) { + if(md_ascii_eq(STR(off), str, len)) { + /* Success. */ + *p_end = off + len; + return TRUE; } - off++; } i++; - if(i >= n_lines) + if(off >= max_end || i >= n_lines) { + /* Failure. */ + *p_scan_horizon = off; return FALSE; + } off = lines[i].beg; - - if(off >= max_end) - return FALSE; } - -done: - if(off >= max_end) - return FALSE; - - *p_end = off+1; - return TRUE; } static int -md_is_html_processing_instruction(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) +md_is_html_comment(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) { OFF off = beg; - int i = 0; MD_ASSERT(CH(beg) == _T('<')); - if(off + 2 >= lines[0].end) + if(off + 4 >= lines[0].end) return FALSE; - if(CH(off+1) != _T('?')) + if(CH(off+1) != _T('!') || CH(off+2) != _T('-') || CH(off+3) != _T('-')) return FALSE; - off += 2; + off += 4; - while(1) { - while(off + 1 < lines[i].end) { - if(CH(off) == _T('?') && CH(off+1) == _T('>')) { - /* Success. */ - off++; - goto done; - } + /* ">" and "->" must not follow the opening. */ + if(off < lines[0].end && CH(off) == _T('>')) + return FALSE; + if(off+1 < lines[0].end && CH(off) == _T('-') && CH(off+1) == _T('>')) + return FALSE; - off++; + /* HTML comment must not contyain "--", so we scan just for "--" instead + * of "-->" and verify manually that '>' follows. */ + if(md_scan_for_html_closer(ctx, _T("--"), 2, + lines, n_lines, off, max_end, p_end, &ctx->html_comment_horizon)) + { + if(*p_end < max_end && CH(*p_end) == _T('>')) { + *p_end = *p_end + 1; + return TRUE; } + } - i++; - if(i >= n_lines) - return FALSE; + return FALSE; +} - off = lines[i].beg; - if(off >= max_end) - return FALSE; - } +static int +md_is_html_processing_instruction(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; -done: - if(off >= max_end) + if(off + 2 >= lines[0].end) return FALSE; + if(CH(off+1) != _T('?')) + return FALSE; + off += 2; - *p_end = off+1; - return TRUE; + return md_scan_for_html_closer(ctx, _T("?>"), 2, + lines, n_lines, off, max_end, p_end, &ctx->html_proc_instr_horizon); } static int md_is_html_declaration(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) { OFF off = beg; - int i = 0; - - MD_ASSERT(CH(beg) == _T('<')); if(off + 2 >= lines[0].end) return FALSE; @@ -1182,31 +1177,8 @@ md_is_html_declaration(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, if(off < lines[0].end && !ISWHITESPACE(off)) return FALSE; - while(1) { - while(off < lines[i].end) { - if(CH(off) == _T('>')) { - /* Success. */ - goto done; - } - - off++; - } - - i++; - if(i >= n_lines) - return FALSE; - - off = lines[i].beg; - if(off >= max_end) - return FALSE; - } - -done: - if(off >= max_end) - return FALSE; - - *p_end = off+1; - return TRUE; + return md_scan_for_html_closer(ctx, _T(">"), 1, + lines, n_lines, off, max_end, p_end, &ctx->html_decl_horizon); } static int @@ -1216,7 +1188,6 @@ md_is_html_cdata(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF ma static const SZ open_size = SIZEOF_ARRAY(open_str) - 1; OFF off = beg; - int i = 0; if(off + open_size >= lines[0].end) return FALSE; @@ -1224,49 +1195,22 @@ md_is_html_cdata(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF ma return FALSE; off += open_size; - while(1) { - while(off + 2 < lines[i].end) { - if(CH(off) == _T(']') && CH(off+1) == _T(']') && CH(off+2) == _T('>')) { - /* Success. */ - off += 2; - goto done; - } - - off++; - } - - i++; - if(i >= n_lines) - return FALSE; - - off = lines[i].beg; - if(off >= max_end) - return FALSE; - } - -done: - if(off >= max_end) - return FALSE; + if(lines[n_lines-1].end < max_end) + max_end = lines[n_lines-1].end - 2; - *p_end = off+1; - return TRUE; + return md_scan_for_html_closer(ctx, _T("]]>"), 3, + lines, n_lines, off, max_end, p_end, &ctx->html_cdata_horizon); } static int md_is_html_any(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) { - if(md_is_html_tag(ctx, lines, n_lines, beg, max_end, p_end) == TRUE) - return TRUE; - if(md_is_html_comment(ctx, lines, n_lines, beg, max_end, p_end) == TRUE) - return TRUE; - if(md_is_html_processing_instruction(ctx, lines, n_lines, beg, max_end, p_end) == TRUE) - return TRUE; - if(md_is_html_declaration(ctx, lines, n_lines, beg, max_end, p_end) == TRUE) - return TRUE; - if(md_is_html_cdata(ctx, lines, n_lines, beg, max_end, p_end) == TRUE) - return TRUE; - - return FALSE; + MD_ASSERT(CH(beg) == _T('<')); + return (md_is_html_tag(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_comment(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_processing_instruction(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_declaration(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_cdata(ctx, lines, n_lines, beg, max_end, p_end)); } @@ -1282,7 +1226,7 @@ md_is_hex_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, O while(off < max_end && ISXDIGIT_(text[off]) && off - beg <= 8) off++; - if(1 <= off - beg && off - beg <= 8) { + if(1 <= off - beg && off - beg <= 6) { *p_end = off; return TRUE; } else { @@ -1298,7 +1242,7 @@ md_is_dec_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, O while(off < max_end && ISDIGIT_(text[off]) && off - beg <= 8) off++; - if(1 <= off - beg && off - beg <= 8) { + if(1 <= off - beg && off - beg <= 7) { *p_end = off; return TRUE; } else { @@ -1551,7 +1495,7 @@ md_link_label_hash(const CHAR* label, SZ size) { unsigned hash = MD_FNV1A_BASE; OFF off; - int codepoint; + unsigned codepoint; int is_whitespace = FALSE; off = md_skip_unicode_whitespace(label, 0, size); @@ -1563,25 +1507,53 @@ md_link_label_hash(const CHAR* label, SZ size) if(is_whitespace) { codepoint = ' '; - hash = md_fnv1a(hash, &codepoint, 1 * sizeof(int)); - + hash = md_fnv1a(hash, &codepoint, sizeof(unsigned)); off = md_skip_unicode_whitespace(label, off, size); } else { MD_UNICODE_FOLD_INFO fold_info; md_get_unicode_fold_info(codepoint, &fold_info); - hash = md_fnv1a(hash, fold_info.codepoints, fold_info.n_codepoints * sizeof(int)); - + hash = md_fnv1a(hash, fold_info.codepoints, fold_info.n_codepoints * sizeof(unsigned)); off += char_size; } } - if(!is_whitespace) { - codepoint = ' '; - hash = md_fnv1a(hash, &codepoint, 1 * sizeof(int)); + return hash; +} + +static OFF +md_link_label_cmp_load_fold_info(const CHAR* label, OFF off, SZ size, + MD_UNICODE_FOLD_INFO* fold_info) +{ + unsigned codepoint; + SZ char_size; + + if(off >= size) { + /* Treat end of link label as a whitespace. */ + goto whitespace; + } + + if(ISNEWLINE_(label[off])) { + /* Treat new lines as a whitespace. */ + off++; + goto whitespace; } - return hash; + codepoint = md_decode_unicode(label, off, size, &char_size); + off += char_size; + if(ISUNICODEWHITESPACE_(codepoint)) { + /* Treat all whitespace as equivalent */ + goto whitespace; + } + + /* Get real folding info. */ + md_get_unicode_fold_info(codepoint, fold_info); + return off; + +whitespace: + fold_info->codepoints[0] = _T(' '); + fold_info->n_codepoints = 1; + return off; } static int @@ -1589,55 +1561,35 @@ md_link_label_cmp(const CHAR* a_label, SZ a_size, const CHAR* b_label, SZ b_size { OFF a_off; OFF b_off; + int a_reached_end = FALSE; + int b_reached_end = FALSE; + MD_UNICODE_FOLD_INFO a_fi = { 0 }; + MD_UNICODE_FOLD_INFO b_fi = { 0 }; + OFF a_fi_off = 0; + OFF b_fi_off = 0; + int cmp; - /* The slow path, with Unicode case folding and Unicode whitespace collapsing. */ a_off = md_skip_unicode_whitespace(a_label, 0, a_size); b_off = md_skip_unicode_whitespace(b_label, 0, b_size); - while(a_off < a_size || b_off < b_size) { - int a_codepoint, b_codepoint; - SZ a_char_size, b_char_size; - int a_is_whitespace, b_is_whitespace; - - if(a_off < a_size) { - a_codepoint = md_decode_unicode(a_label, a_off, a_size, &a_char_size); - a_is_whitespace = ISUNICODEWHITESPACE_(a_codepoint) || ISNEWLINE_(a_label[a_off]); - } else { - /* Treat end of label as a whitespace. */ - a_codepoint = -1; - a_is_whitespace = TRUE; + while(!a_reached_end && !b_reached_end) { + /* If needed, load fold info for next char. */ + if(a_fi_off >= a_fi.n_codepoints) { + a_fi_off = 0; + a_off = md_link_label_cmp_load_fold_info(a_label, a_off, a_size, &a_fi); + a_reached_end = (a_off >= a_size); } - - if(b_off < b_size) { - b_codepoint = md_decode_unicode(b_label, b_off, b_size, &b_char_size); - b_is_whitespace = ISUNICODEWHITESPACE_(b_codepoint) || ISNEWLINE_(b_label[b_off]); - } else { - /* Treat end of label as a whitespace. */ - b_codepoint = -1; - b_is_whitespace = TRUE; + if(b_fi_off >= b_fi.n_codepoints) { + b_fi_off = 0; + b_off = md_link_label_cmp_load_fold_info(b_label, b_off, b_size, &b_fi); + b_reached_end = (b_off >= b_size); } - if(a_is_whitespace || b_is_whitespace) { - if(!a_is_whitespace || !b_is_whitespace) - return (a_is_whitespace ? -1 : +1); - - a_off = md_skip_unicode_whitespace(a_label, a_off, a_size); - b_off = md_skip_unicode_whitespace(b_label, b_off, b_size); - } else { - MD_UNICODE_FOLD_INFO a_fold_info, b_fold_info; - int cmp; - - md_get_unicode_fold_info(a_codepoint, &a_fold_info); - md_get_unicode_fold_info(b_codepoint, &b_fold_info); + cmp = b_fi.codepoints[b_fi_off] - a_fi.codepoints[a_fi_off]; + if(cmp != 0) + return cmp; - if(a_fold_info.n_codepoints != b_fold_info.n_codepoints) - return (a_fold_info.n_codepoints - b_fold_info.n_codepoints); - cmp = memcmp(a_fold_info.codepoints, b_fold_info.codepoints, a_fold_info.n_codepoints * sizeof(int)); - if(cmp != 0) - return cmp; - - a_off += a_char_size; - b_off += b_char_size; - } + a_fi_off++; + b_fi_off++; } return 0; @@ -1911,7 +1863,7 @@ md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, return FALSE; } } else { - int codepoint; + unsigned codepoint; SZ char_size; codepoint = md_decode_unicode(ctx->text, off, ctx->size, &char_size); @@ -1958,7 +1910,7 @@ md_is_link_destination_A(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, continue; } - if(ISWHITESPACE(off) || CH(off) == _T('<')) + if(ISNEWLINE(off) || CH(off) == _T('<')) return FALSE; if(CH(off) == _T('>')) { @@ -2017,6 +1969,16 @@ md_is_link_destination_B(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, return TRUE; } +static inline int +md_is_link_destination(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, + OFF* p_contents_beg, OFF* p_contents_end) +{ + if(CH(beg) == _T('<')) + return md_is_link_destination_A(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end); + else + return md_is_link_destination_B(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end); +} + static int md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF* p_end, int* p_beg_line_index, int* p_end_line_index, @@ -2026,7 +1988,7 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, CHAR closer_char; int line_index = 0; - /* Optional white space with up to one line break. */ + /* White space with up to one line break. */ while(off < lines[line_index].end && ISWHITESPACE(off)) off++; if(off >= lines[line_index].end) { @@ -2035,6 +1997,8 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, return FALSE; off = lines[line_index].beg; } + if(off == beg) + return FALSE; *p_beg_line_index = line_index; @@ -2061,6 +2025,9 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, *p_end = off+1; *p_end_line_index = line_index; return TRUE; + } else if(closer_char == _T(')') && CH(off) == _T('(')) { + /* ()-style title cannot contain (unescaped '(')) */ + return FALSE; } off++; @@ -2081,9 +2048,7 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, * Returns -1 in case of an error (out of memory). */ static int -md_is_link_reference_definition_helper( - MD_CTX* ctx, const MD_LINE* lines, int n_lines, - int (*is_link_dest_fn)(MD_CTX*, OFF, OFF, OFF*, OFF*, OFF*)) +md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) { OFF label_contents_beg; OFF label_contents_end; @@ -2127,8 +2092,8 @@ md_is_link_reference_definition_helper( } /* Link destination. */ - if(!is_link_dest_fn(ctx, off, lines[line_index].end, - &off, &dest_contents_beg, &dest_contents_end)) + if(!md_is_link_destination(ctx, off, lines[line_index].end, + &off, &dest_contents_beg, &dest_contents_end)) return FALSE; /* (Optional) title. Note we interpret it as an title only if nothing @@ -2214,16 +2179,6 @@ abort: return -1; } -static inline int -md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) -{ - int ret; - ret = md_is_link_reference_definition_helper(ctx, lines, n_lines, md_is_link_destination_A); - if(ret == 0) - ret = md_is_link_reference_definition_helper(ctx, lines, n_lines, md_is_link_destination_B); - return ret; -} - static int md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF end, MD_LINK_ATTR* attr) @@ -2279,9 +2234,8 @@ abort: } static int -md_is_inline_link_spec_helper(MD_CTX* ctx, const MD_LINE* lines, int n_lines, - OFF beg, OFF* p_end, MD_LINK_ATTR* attr, - int (*is_link_dest_fn)(MD_CTX*, OFF, OFF, OFF*, OFF*, OFF*)) +md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines, + OFF beg, OFF* p_end, MD_LINK_ATTR* attr) { int line_index = 0; int tmp_line_index; @@ -2321,7 +2275,7 @@ md_is_inline_link_spec_helper(MD_CTX* ctx, const MD_LINE* lines, int n_lines, } /* Link destination. */ - if(!is_link_dest_fn(ctx, off, lines[line_index].end, + if(!md_is_link_destination(ctx, off, lines[line_index].end, &off, &attr->dest_beg, &attr->dest_end)) return FALSE; @@ -2376,14 +2330,6 @@ abort: return ret; } -static inline int -md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines, - OFF beg, OFF* p_end, MD_LINK_ATTR* attr) -{ - return md_is_inline_link_spec_helper(ctx, lines, n_lines, beg, p_end, attr, md_is_link_destination_A) || - md_is_inline_link_spec_helper(ctx, lines, n_lines, beg, p_end, attr, md_is_link_destination_B); -} - static void md_free_ref_defs(MD_CTX* ctx) { @@ -2493,13 +2439,42 @@ struct MD_MARK_tag { /* Mark flags specific for various mark types (so they can share bits). */ #define MD_MARK_EMPH_INTRAWORD 0x20 /* Helper for the "rule of 3". */ -#define MD_MARK_EMPH_MODULO3_0 0x40 -#define MD_MARK_EMPH_MODULO3_1 0x80 -#define MD_MARK_EMPH_MODULO3_2 (0x40 | 0x80) -#define MD_MARK_EMPH_MODULO3_MASK (0x40 | 0x80) +#define MD_MARK_EMPH_MOD3_0 0x40 +#define MD_MARK_EMPH_MOD3_1 0x80 +#define MD_MARK_EMPH_MOD3_2 (0x40 | 0x80) +#define MD_MARK_EMPH_MOD3_MASK (0x40 | 0x80) #define MD_MARK_AUTOLINK 0x20 /* Distinguisher for '<', '>'. */ #define MD_MARK_VALIDPERMISSIVEAUTOLINK 0x20 /* For permissive autolinks. */ +static MD_MARKCHAIN* +md_asterisk_chain(MD_CTX* ctx, unsigned flags) +{ + switch(flags & (MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_MASK)) { + case MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_0: return &ASTERISK_OPENERS_intraword_mod3_0; + case MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_1: return &ASTERISK_OPENERS_intraword_mod3_1; + case MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_2: return &ASTERISK_OPENERS_intraword_mod3_2; + case MD_MARK_EMPH_MOD3_0: return &ASTERISK_OPENERS_extraword_mod3_0; + case MD_MARK_EMPH_MOD3_1: return &ASTERISK_OPENERS_extraword_mod3_1; + case MD_MARK_EMPH_MOD3_2: return &ASTERISK_OPENERS_extraword_mod3_2; + default: MD_UNREACHABLE(); + } + return NULL; +} + +static MD_MARKCHAIN* +md_mark_chain(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + switch(mark->ch) { + case _T('*'): return md_asterisk_chain(ctx, mark->flags); + case _T('_'): return &UNDERSCORE_OPENERS; + case _T('~'): return &TILDE_OPENERS; + case _T('['): return &BRACKET_OPENERS; + case _T('|'): return &TABLECELLBOUNDARIES; + default: return NULL; + } +} static MD_MARK* md_push_mark(MD_CTX* ctx) @@ -2658,18 +2633,11 @@ md_rollback(MD_CTX* ctx, int opener_index, int closer_index, int how) MD_MARKCHAIN* chain; mark_opener->flags &= ~(MD_MARK_OPENER | MD_MARK_CLOSER | MD_MARK_RESOLVED); - - switch(mark_opener->ch) { - case '*': chain = &ASTERISK_OPENERS; break; - case '_': chain = &UNDERSCORE_OPENERS; break; - case '`': chain = &BACKTICK_OPENERS; break; - case '<': chain = &LOWERTHEN_OPENERS; break; - case '~': chain = &TILDE_OPENERS; break; - default: MD_UNREACHABLE(); break; + chain = md_mark_chain(ctx, opener_index); + if(chain != NULL) { + md_mark_chain_append(ctx, chain, mark_opener_index); + discard_flag = 1; } - md_mark_chain_append(ctx, chain, mark_opener_index); - - discard_flag = 1; } } @@ -2730,19 +2698,250 @@ md_build_mark_char_map(MD_CTX* ctx) if(ctx->parser.flags & MD_FLAG_COLLAPSEWHITESPACE) { int i; - for(i = 0; i < sizeof(ctx->mark_char_map); i++) { + for(i = 0; i < (int) sizeof(ctx->mark_char_map); i++) { if(ISWHITESPACE_(i)) ctx->mark_char_map[i] = 1; } } } +/* We limit code span marks to lower then 32 backticks. This solves the + * pathologic case of too many openers, each of different length: Their + * resolving would be then O(n^2). */ +#define CODESPAN_MARK_MAXLEN 32 + static int -md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) +md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, + OFF* p_opener_beg, OFF* p_opener_end, + OFF* p_closer_beg, OFF* p_closer_end, + OFF last_potential_closers[CODESPAN_MARK_MAXLEN], + int* p_reached_paragraph_end) +{ + OFF opener_beg = beg; + OFF opener_end; + OFF closer_beg; + OFF closer_end; + SZ mark_len; + OFF line_end; + int has_space_after_opener = FALSE; + int has_eol_after_opener = FALSE; + int has_space_before_closer = FALSE; + int has_eol_before_closer = FALSE; + int has_only_space = TRUE; + int line_index = 0; + + line_end = lines[0].end; + opener_end = opener_beg; + while(opener_end < line_end && CH(opener_end) == _T('`')) + opener_end++; + has_space_after_opener = (opener_end < line_end && CH(opener_end) == _T(' ')); + has_eol_after_opener = (opener_end == line_end); + + /* The caller needs to know end of the opening mark even if we fail. */ + *p_opener_end = opener_end; + + mark_len = opener_end - opener_beg; + if(mark_len > CODESPAN_MARK_MAXLEN) + return FALSE; + + /* Check whether we already know there is no closer of this length. + * If so, re-scan does no sense. This fixes issue #59. */ + if(last_potential_closers[mark_len-1] >= lines[n_lines-1].end || + (*p_reached_paragraph_end && last_potential_closers[mark_len-1] < opener_end)) + return FALSE; + + closer_beg = opener_end; + closer_end = opener_end; + + /* Find closer mark. */ + while(TRUE) { + while(closer_beg < line_end && CH(closer_beg) != _T('`')) { + if(CH(closer_beg) != _T(' ')) + has_only_space = FALSE; + closer_beg++; + } + closer_end = closer_beg; + while(closer_end < line_end && CH(closer_end) == _T('`')) + closer_end++; + + if(closer_end - closer_beg == mark_len) { + /* Success. */ + has_space_before_closer = (closer_beg > lines[line_index].beg && CH(closer_beg-1) == _T(' ')); + has_eol_before_closer = (closer_beg == lines[line_index].beg); + break; + } + + if(closer_end - closer_beg > 0) { + /* We have found a back-tick which is not part of the closer. */ + has_only_space = FALSE; + + /* But if we eventually fail, remember it as a potential closer + * of its own length for future attempts. This mitigates needs for + * rescans. */ + if(closer_end - closer_beg < CODESPAN_MARK_MAXLEN) { + if(closer_beg > last_potential_closers[closer_end - closer_beg - 1]) + last_potential_closers[closer_end - closer_beg - 1] = closer_beg; + } + } + + if(closer_end >= line_end) { + line_index++; + if(line_index >= n_lines) { + /* Reached end of the paragraph and still nothing. */ + *p_reached_paragraph_end = TRUE; + return FALSE; + } + /* Try on the next line. */ + line_end = lines[line_index].end; + closer_beg = lines[line_index].beg; + } else { + closer_beg = closer_end; + } + } + + /* If there is a space or a new line both after and before the opener + * (and if the code span is not made of spaces only), consume one initial + * and one trailing space as part of the marks. */ + if(!has_only_space && + (has_space_after_opener || has_eol_after_opener) && + (has_space_before_closer || has_eol_before_closer)) + { + if(has_space_after_opener) + opener_end++; + else + opener_end = lines[1].beg; + + if(has_space_before_closer) + closer_beg--; + else { + closer_beg = lines[line_index-1].end; + /* We need to eat the preceding "\r\n" but not any line trailing + * spaces. */ + while(closer_beg < ctx->size && ISBLANK(closer_beg)) + closer_beg++; + } + } + + *p_opener_beg = opener_beg; + *p_opener_end = opener_end; + *p_closer_beg = closer_beg; + *p_closer_end = closer_end; + return TRUE; +} + +static int +md_is_autolink_uri(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg+1; + + MD_ASSERT(CH(beg) == _T('<')); + + /* Check for scheme. */ + if(off >= max_end || !ISASCII(off)) + return FALSE; + off++; + while(1) { + if(off >= max_end) + return FALSE; + if(off - beg > 32) + return FALSE; + if(CH(off) == _T(':') && off - beg >= 3) + break; + if(!ISALNUM(off) && CH(off) != _T('+') && CH(off) != _T('-') && CH(off) != _T('.')) + return FALSE; + off++; + } + + /* Check the path after the scheme. */ + while(off < max_end && CH(off) != _T('>')) { + if(ISWHITESPACE(off) || ISCNTRL(off) || CH(off) == _T('<')) + return FALSE; + off++; + } + + if(off >= max_end) + return FALSE; + + MD_ASSERT(CH(off) == _T('>')); + *p_end = off+1; + return TRUE; +} + +static int +md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg + 1; + int label_len; + + MD_ASSERT(CH(beg) == _T('<')); + + /* The code should correspond to this regexp: + /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+ + @[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? + (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ + */ + + /* Username (before '@'). */ + while(off < max_end && (ISALNUM(off) || ISANYOF(off, _T(".!#$%&'*+/=?^_`{|}~-")))) + off++; + if(off <= beg+1) + return FALSE; + + /* '@' */ + if(off >= max_end || CH(off) != _T('@')) + return FALSE; + off++; + + /* Labels delimited with '.'; each label is sequence of 1 - 62 alnum + * characters or '-', but '-' is not allowed as first or last char. */ + label_len = 0; + while(off < max_end) { + if(ISALNUM(off)) + label_len++; + else if(CH(off) == _T('-') && label_len > 0) + label_len++; + else if(CH(off) == _T('.') && label_len > 0 && CH(off-1) != _T('-')) + label_len = 0; + else + break; + + if(label_len > 62) + return FALSE; + + off++; + } + + if(label_len <= 0 || off >= max_end || CH(off) != _T('>') || CH(off-1) == _T('-')) + return FALSE; + + *p_end = off+1; + return TRUE; +} + +static int +md_is_autolink(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, int* p_missing_mailto) +{ + if(md_is_autolink_uri(ctx, beg, max_end, p_end)) { + *p_missing_mailto = FALSE; + return TRUE; + } + + if(md_is_autolink_email(ctx, beg, max_end, p_end)) { + *p_missing_mailto = TRUE; + return TRUE; + } + + return FALSE; +} + +static int +md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) { int i; int ret = 0; MD_MARK* mark; + OFF codespan_last_potential_closers[CODESPAN_MARK_MAXLEN] = { 0 }; + int codespan_scanned_till_paragraph_end = FALSE; for(i = 0; i < n_lines; i++) { const MD_LINE* line = &lines[i]; @@ -2761,8 +2960,8 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) #define IS_MARK_CHAR(off) (ctx->mark_char_map[(unsigned char) CH(off)]) #endif - /* Optimization: Fast path (with some loop unrolling). */ - while(off + 4 < line_end && !IS_MARK_CHAR(off+0) && !IS_MARK_CHAR(off+1) + /* Optimization: Use some loop unrolling. */ + while(off + 3 < line_end && !IS_MARK_CHAR(off+0) && !IS_MARK_CHAR(off+1) && !IS_MARK_CHAR(off+2) && !IS_MARK_CHAR(off+3)) off += 4; while(off < line_end && !IS_MARK_CHAR(off+0)) @@ -2780,14 +2979,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) /* Hard-break cannot be on the last line of the block. */ if(!ISNEWLINE(off+1) || i+1 < n_lines) PUSH_MARK(ch, off, off+2, MD_MARK_RESOLVED); - - /* If '`' or '>' follows, we need both marks as the backslash - * may be inside a code span or an autolink where escaping is - * disabled. */ - if(CH(off+1) == _T('`') || CH(off+1) == _T('>')) - off++; - else - off += 2; + off += 2; continue; } @@ -2835,9 +3027,9 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) * split the mark when being later resolved partially by some * shorter closer. */ switch((tmp - off) % 3) { - case 0: flags |= MD_MARK_EMPH_MODULO3_0; break; - case 1: flags |= MD_MARK_EMPH_MODULO3_1; break; - case 2: flags |= MD_MARK_EMPH_MODULO3_2; break; + case 0: flags |= MD_MARK_EMPH_MOD3_0; break; + case 1: flags |= MD_MARK_EMPH_MOD3_1; break; + case 2: flags |= MD_MARK_EMPH_MOD3_2; break; } PUSH_MARK(ch, off, tmp, flags); @@ -2860,18 +3052,32 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) /* A potential code span start/end. */ if(ch == _T('`')) { - OFF tmp = off+1; - - while(tmp < line_end && CH(tmp) == _T('`')) - tmp++; - - /* We limit code span marks to lower then 256 backticks. This - * solves a pathologic case of too many openers, each of - * different length: Their resolving is then O(n^2). */ - if(tmp - off < 256) - PUSH_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER); + OFF opener_beg, opener_end; + OFF closer_beg, closer_end; + int is_code_span; + + is_code_span = md_is_code_span(ctx, lines + i, n_lines - i, off, + &opener_beg, &opener_end, &closer_beg, &closer_end, + codespan_last_potential_closers, + &codespan_scanned_till_paragraph_end); + if(is_code_span) { + PUSH_MARK(_T('`'), opener_beg, opener_end, MD_MARK_OPENER | MD_MARK_RESOLVED); + PUSH_MARK(_T('`'), closer_beg, closer_end, MD_MARK_CLOSER | MD_MARK_RESOLVED); + ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1; + ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2; + + off = closer_end; + + /* Advance the current line accordingly. */ + while(off > line_end) { + i++; + line++; + line_end = line->end; + } + continue; + } - off = tmp; + off = opener_end; continue; } @@ -2893,9 +3099,49 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) } /* A potential autolink or raw HTML start/end. */ - if(ch == _T('<') || ch == _T('>')) { - if(!(ctx->parser.flags & MD_FLAG_NOHTMLSPANS)) - PUSH_MARK(ch, off, off+1, (ch == _T('<') ? MD_MARK_POTENTIAL_OPENER : MD_MARK_POTENTIAL_CLOSER)); + if(ch == _T('<')) { + int is_autolink; + OFF autolink_end; + int missing_mailto; + + if(!(ctx->parser.flags & MD_FLAG_NOHTMLSPANS)) { + int is_html; + OFF html_end; + + /* Given the nature of the raw HTML, we have to recognize + * it here. Doing so later in md_analyze_lt_gt() could + * open can of worms of quadratic complexity. */ + is_html = md_is_html_any(ctx, lines + i, n_lines - i, off, + lines[n_lines-1].end, &html_end); + if(is_html) { + PUSH_MARK(_T('<'), off, off, MD_MARK_OPENER | MD_MARK_RESOLVED); + PUSH_MARK(_T('>'), html_end, html_end, MD_MARK_CLOSER | MD_MARK_RESOLVED); + ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1; + ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2; + off = html_end; + + /* Advance the current line accordingly. */ + while(off > line_end) { + i++; + line++; + line_end = line->end; + } + continue; + } + } + + is_autolink = md_is_autolink(ctx, off, lines[n_lines-1].end, + &autolink_end, &missing_mailto); + if(is_autolink) { + PUSH_MARK((missing_mailto ? _T('@') : _T('<')), off, off+1, + MD_MARK_OPENER | MD_MARK_RESOLVED | MD_MARK_AUTOLINK); + PUSH_MARK(_T('>'), autolink_end-1, autolink_end, + MD_MARK_CLOSER | MD_MARK_RESOLVED | MD_MARK_AUTOLINK); + ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1; + ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2; + off = autolink_end; + continue; + } off++; continue; @@ -2947,7 +3193,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) }; int scheme_index; - for(scheme_index = 0; scheme_index < SIZEOF_ARRAY(scheme_map); scheme_index++) { + for(scheme_index = 0; scheme_index < (int) SIZEOF_ARRAY(scheme_map); scheme_index++) { const CHAR* scheme = scheme_map[scheme_index].scheme; const SZ scheme_size = scheme_map[scheme_index].scheme_size; const CHAR* suffix = scheme_map[scheme_index].suffix; @@ -3002,6 +3248,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) PUSH_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER); off = tmp; + continue; } /* Turn non-trivial whitespace into single space. */ @@ -3012,254 +3259,29 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) tmp++; if(tmp - off > 1 || ch != _T(' ')) - PUSH_MARK(ch, off, tmp, MD_MARK_RESOLVED); - - off = tmp; - continue; - } - - /* NULL character. */ - if(ch == _T('\0')) { - PUSH_MARK(ch, off, off+1, MD_MARK_RESOLVED); - off++; - continue; - } - - off++; - } - } - - /* Add a dummy mark at the end of the mark vector to simplify - * process_inlines(). */ - PUSH_MARK(127, ctx->size, ctx->size, MD_MARK_RESOLVED); - -abort: - return ret; -} - - -/* Analyze whether the back-tick is really start/end mark of a code span. - * If yes, reset all marks inside of it and setup flags of both marks. */ -static void -md_analyze_backtick(MD_CTX* ctx, int mark_index) -{ - MD_MARK* mark = &ctx->marks[mark_index]; - int opener_index = BACKTICK_OPENERS.tail; - - /* Try to find unresolved opener of the same length. If we find it, - * we form a code span. */ - while(opener_index >= 0) { - MD_MARK* opener = &ctx->marks[opener_index]; - - if(opener->end - opener->beg == mark->end - mark->beg) { - /* Rollback anything found inside it. - * (e.g. the code span contains some back-ticks or other special - * chars we misinterpreted.) */ - md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_ALL); - - /* Resolve the span. */ - md_resolve_range(ctx, &BACKTICK_OPENERS, opener_index, mark_index); - - /* Append any space or new line inside the span into the mark - * itself to swallow it. */ - while(CH(opener->end) == _T(' ') || ISNEWLINE(opener->end)) - opener->end++; - if(mark->beg > opener->end) { - while(CH(mark->beg-1) == _T(' ') || ISNEWLINE(mark->beg-1)) - mark->beg--; - } - - /* Done. */ - return; - } - - opener_index = ctx->marks[opener_index].prev; - } - - /* We didn't find any matching opener, so we ourselves may be the opener - * of some upcoming closer. We also have to handle specially if there is - * a backslash mark before it as that can cancel the first backtick. */ - if(mark_index > 0 && (mark-1)->beg == mark->beg - 1 && (mark-1)->ch == '\\') { - if(mark->end - mark->beg == 1) { - /* Single escaped backtick. */ - return; - } - - /* Remove the escaped backtick from the opener. */ - mark->beg++; - } - - if(mark->flags & MD_MARK_POTENTIAL_OPENER) - md_mark_chain_append(ctx, &BACKTICK_OPENERS, mark_index); -} - -static int -md_is_autolink_uri(MD_CTX* ctx, OFF beg, OFF end) -{ - OFF off = beg; - - /* Check for scheme. */ - if(off >= end || !ISASCII(off)) - return FALSE; - off++; - while(1) { - if(off >= end) - return FALSE; - if(off - beg > 32) - return FALSE; - if(CH(off) == _T(':') && off - beg >= 2) - break; - if(!ISALNUM(off) && CH(off) != _T('+') && CH(off) != _T('-') && CH(off) != _T('.')) - return FALSE; - off++; - } - - /* Check the path after the scheme. */ - while(off < end) { - if(ISWHITESPACE(off) || ISCNTRL(off) || CH(off) == _T('<') || CH(off) == _T('>')) - return FALSE; - off++; - } - - return TRUE; -} - -static int -md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF end) -{ - OFF off = beg; - int label_len; - - /* The code should correspond to this regexp: - /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+ - @[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? - (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ - */ - - /* Username (before '@'). */ - while(off < end && (ISALNUM(off) || ISANYOF(off, _T(".!#$%&'*+/=?^_`{|}~-")))) - off++; - if(off <= beg) - return FALSE; - - /* '@' */ - if(off >= end || CH(off) != _T('@')) - return FALSE; - off++; - - /* Labels delimited with '.'; each label is sequence of 1 - 62 alnum - * characters or '-', but '-' is not allowed as first or last char. */ - label_len = 0; - while(off < end) { - if(ISALNUM(off)) - label_len++; - else if(CH(off) == _T('-') && label_len > 0) - label_len++; - else if(CH(off) == _T('.') && label_len > 0 && CH(off-1) != _T('-')) - label_len = 0; - else - return FALSE; - - if(label_len > 63) - return FALSE; - - off++; - } - - if(label_len <= 0 || CH(off-1) == _T('-')) - return FALSE; - - return TRUE; -} - -static int -md_is_autolink(MD_CTX* ctx, OFF beg, OFF end, int* p_missing_mailto) -{ - MD_ASSERT(CH(beg) == _T('<')); - MD_ASSERT(CH(end-1) == _T('>')); - - beg++; - end--; - - if(md_is_autolink_uri(ctx, beg, end)) - return TRUE; - - if(md_is_autolink_email(ctx, beg, end)) { - *p_missing_mailto = 1; - return TRUE; - } - - return FALSE; -} - -static void -md_analyze_lt_gt(MD_CTX* ctx, int mark_index, const MD_LINE* lines, int n_lines) -{ - MD_MARK* mark = &ctx->marks[mark_index]; - int opener_index; - - /* If it is an opener ('<'), remember it. */ - if(mark->flags & MD_MARK_POTENTIAL_OPENER) { - md_mark_chain_append(ctx, &LOWERTHEN_OPENERS, mark_index); - return; - } - - /* Otherwise we are potential closer and we try to resolve with since all - * the chained unresolved openers. */ - opener_index = LOWERTHEN_OPENERS.head; - while(opener_index >= 0) { - MD_MARK* opener = &ctx->marks[opener_index]; - OFF detected_end; - int is_autolink = 0; - int is_missing_mailto = 0; - int is_raw_html = 0; - - is_autolink = (md_is_autolink(ctx, opener->beg, mark->end, &is_missing_mailto)); - - if(is_autolink) { - if(is_missing_mailto) - opener->ch = _T('@'); - } else { - /* Identify the line where the opening mark lives. */ - int line_index = 0; - while(1) { - if(opener->beg < lines[line_index].end) - break; - line_index++; - } - - is_raw_html = (md_is_html_any(ctx, lines + line_index, - n_lines - line_index, opener->beg, mark->end, &detected_end)); - } - - /* Check whether the range forms a valid raw HTML. */ - if(is_autolink || is_raw_html) { - md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_ALL); - md_resolve_range(ctx, &LOWERTHEN_OPENERS, opener_index, mark_index); - - if(is_raw_html) { - /* If this fails, it means we have missed some earlier opportunity - * to resolve the opener of raw HTML. */ - MD_ASSERT(detected_end == mark->end); + PUSH_MARK(ch, off, tmp, MD_MARK_RESOLVED); - /* Make these marks zero width so the '<' and '>' are part of its - * contents. */ - opener->end = opener->beg; - mark->beg = mark->end; + off = tmp; + continue; + } - opener->flags &= ~MD_MARK_AUTOLINK; - mark->flags &= ~MD_MARK_AUTOLINK; - } else { - opener->flags |= MD_MARK_AUTOLINK; - mark->flags |= MD_MARK_AUTOLINK; + /* NULL character. */ + if(ch == _T('\0')) { + PUSH_MARK(ch, off, off+1, MD_MARK_RESOLVED); + off++; + continue; } - /* And we are done. */ - return; + off++; } - - opener_index = opener->next; } + + /* Add a dummy mark at the end of the mark vector to simplify + * process_inlines(). */ + PUSH_MARK(127, ctx->size, ctx->size, MD_MARK_RESOLVED); + +abort: + return ret; } static void @@ -3501,7 +3523,7 @@ md_analyze_table_cell_boundary(MD_CTX* ctx, int mark_index) * follows. */ static int -md_split_simple_pairing_mark(MD_CTX* ctx, int mark_index, SZ n) +md_split_emph_mark(MD_CTX* ctx, int mark_index, SZ n) { MD_MARK* mark = &ctx->marks[mark_index]; int new_mark_index = mark_index + (mark->end - mark->beg - n); @@ -3518,79 +3540,77 @@ md_split_simple_pairing_mark(MD_CTX* ctx, int mark_index, SZ n) } static void -md_analyze_simple_pairing_mark(MD_CTX* ctx, MD_MARKCHAIN* chain, int mark_index, - int apply_rule_of_three) +md_analyze_emph(MD_CTX* ctx, int mark_index) { MD_MARK* mark = &ctx->marks[mark_index]; + MD_MARKCHAIN* chain = md_mark_chain(ctx, mark_index); /* If we can be a closer, try to resolve with the preceding opener. */ - if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && chain->tail >= 0) { - int opener_index = chain->tail; - MD_MARK* opener = &ctx->marks[opener_index]; - SZ opener_size = opener->end - opener->beg; - SZ closer_size = mark->end - mark->beg; - - /* Apply the "rule of three". */ - if(apply_rule_of_three) { - while((mark->flags & MD_MARK_EMPH_INTRAWORD) || (opener->flags & MD_MARK_EMPH_INTRAWORD)) { - SZ opener_orig_size_modulo3; - - switch(opener->flags & MD_MARK_EMPH_MODULO3_MASK) { - case MD_MARK_EMPH_MODULO3_0: opener_orig_size_modulo3 = 0; break; - case MD_MARK_EMPH_MODULO3_1: opener_orig_size_modulo3 = 1; break; - case MD_MARK_EMPH_MODULO3_2: opener_orig_size_modulo3 = 2; break; - default: MD_UNREACHABLE(); break; + if(mark->flags & MD_MARK_POTENTIAL_CLOSER) { + MD_MARK* opener = NULL; + int opener_index; + + if(mark->ch == _T('*')) { + MD_MARKCHAIN* opener_chains[6]; + int i, n_opener_chains; + unsigned flags = mark->flags; + + /* Apply "rule of three". (This is why we break asterisk opener + * marks into multiple chains.) */ + n_opener_chains = 0; + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_intraword_mod3_0; + if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2) + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_intraword_mod3_1; + if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1) + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_intraword_mod3_2; + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_extraword_mod3_0; + if(!(flags & MD_MARK_EMPH_INTRAWORD) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2) + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_extraword_mod3_1; + if(!(flags & MD_MARK_EMPH_INTRAWORD) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1) + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_extraword_mod3_2; + + /* Opener is the most recent mark from the allowed chains. */ + for(i = 0; i < n_opener_chains; i++) { + if(opener_chains[i]->tail >= 0) { + int tmp_index = opener_chains[i]->tail; + MD_MARK* tmp_mark = &ctx->marks[tmp_index]; + if(opener == NULL || tmp_mark->end > opener->end) { + opener_index = tmp_index; + opener = tmp_mark; + } } + } + } else { + /* Simple emph. mark */ + if(chain->tail >= 0) { + opener_index = chain->tail; + opener = &ctx->marks[opener_index]; + } + } - if((opener_orig_size_modulo3 + closer_size) % 3 != 0) { - /* This opener is suitable. */ - break; - } + /* Resolve, if we have found matching opener. */ + if(opener != NULL) { + SZ opener_size = opener->end - opener->beg; + SZ closer_size = mark->end - mark->beg; - if(opener->prev >= 0) { - /* Try previous opener. */ - opener_index = opener->prev; - opener = &ctx->marks[opener_index]; - opener_size = opener->end - opener->beg; - closer_size = mark->end - mark->beg; - } else { - /* No suitable opener found. */ - goto cannot_resolve; - } + if(opener_size > closer_size) { + opener_index = md_split_emph_mark(ctx, opener_index, closer_size); + md_mark_chain_append(ctx, md_mark_chain(ctx, opener_index), opener_index); + } else if(opener_size < closer_size) { + md_split_emph_mark(ctx, mark_index, closer_size - opener_size); } - } - if(opener_size > closer_size) { - opener_index = md_split_simple_pairing_mark(ctx, opener_index, closer_size); - md_mark_chain_append(ctx, chain, opener_index); - } else if(opener_size < closer_size) { - md_split_simple_pairing_mark(ctx, mark_index, closer_size - opener_size); + md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING); + md_resolve_range(ctx, chain, opener_index, mark_index); + return; } - - md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING); - md_resolve_range(ctx, chain, opener_index, mark_index); - return; } -cannot_resolve: - /* If not resolved, and we can be an opener, remember the mark for - * the future. */ + /* If we could not resolve as closer, we may be yet be an opener. */ if(mark->flags & MD_MARK_POTENTIAL_OPENER) md_mark_chain_append(ctx, chain, mark_index); } -static inline void -md_analyze_asterisk(MD_CTX* ctx, int mark_index) -{ - md_analyze_simple_pairing_mark(ctx, &ASTERISK_OPENERS, mark_index, 1); -} - -static inline void -md_analyze_underscore(MD_CTX* ctx, int mark_index) -{ - md_analyze_simple_pairing_mark(ctx, &UNDERSCORE_OPENERS, mark_index, 1); -} - static void md_analyze_tilde(MD_CTX* ctx, int mark_index) { @@ -3618,55 +3638,57 @@ md_analyze_permissive_url_autolink(MD_CTX* ctx, int mark_index) MD_MARK* closer = &ctx->marks[closer_index]; MD_MARK* next_resolved_mark; OFF off = opener->end; - int seen_dot = FALSE; - int seen_underscore_or_hyphen[2] = { FALSE, FALSE }; + int n_dots = FALSE; + int has_underscore_in_last_seg = FALSE; + int has_underscore_in_next_to_last_seg = FALSE; + int n_opened_parenthesis = 0; /* Check for domain. */ while(off < ctx->size) { - if(ISALNUM(off)) { + if(ISALNUM(off) || CH(off) == _T('-')) { off++; } else if(CH(off) == _T('.')) { - seen_dot = TRUE; - seen_underscore_or_hyphen[0] = seen_underscore_or_hyphen[1]; - seen_underscore_or_hyphen[1] = FALSE; + /* We must see at least one period. */ + n_dots++; + has_underscore_in_next_to_last_seg = has_underscore_in_last_seg; + has_underscore_in_last_seg = FALSE; off++; - } else if(ISANYOF2(off, _T('-'), _T('_'))) { - seen_underscore_or_hyphen[1] = TRUE; + } else if(CH(off) == _T('_')) { + /* No underscore may be present in the last two domain segments. */ + has_underscore_in_last_seg = TRUE; off++; } else { break; } } - - if(off <= opener->end || !seen_dot || seen_underscore_or_hyphen[0] || seen_underscore_or_hyphen[1]) + if(off > opener->end && CH(off-1) == _T('.')) { + off--; + n_dots--; + } + if(off <= opener->end || n_dots == 0 || has_underscore_in_next_to_last_seg || has_underscore_in_last_seg) return; /* Check for path. */ next_resolved_mark = closer + 1; while(next_resolved_mark->ch == 'D' || !(next_resolved_mark->flags & MD_MARK_RESOLVED)) next_resolved_mark++; - while(off < next_resolved_mark->beg && CH(off) != _T('<') && !ISWHITESPACE(off) && !ISNEWLINE(off)) - off++; - - /* Path validation. */ - if(ISANYOF(off-1, _T("?!.,:*_~)"))) { - if(CH(off-1) != _T(')')) { - off--; - } else { - int parenthesis_balance = 0; - OFF tmp; - - for(tmp = opener->end; tmp < off; tmp++) { - if(CH(tmp) == _T('(')) - parenthesis_balance++; - else if(CH(tmp) == _T(')')) - parenthesis_balance--; - } - - if(parenthesis_balance < 0) - off--; + while(off < next_resolved_mark->beg && CH(off) != _T('<') && !ISWHITESPACE(off) && !ISNEWLINE(off)) { + /* Parenthesis must be balanced. */ + if(CH(off) == _T('(')) { + n_opened_parenthesis++; + } else if(CH(off) == _T(')')) { + if(n_opened_parenthesis > 0) + n_opened_parenthesis--; + else + break; } + + off++; } + /* These cannot be last char In such case they are more likely normal + * punctuation. */ + if(ISANYOF(off-1, _T("?!.,:*_~"))) + off--; /* Ok. Lets call it auto-link. Adapt opener and create closer to zero * length so all the contents becomes the link text. */ @@ -3755,16 +3777,13 @@ md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, /* Analyze the mark. */ switch(mark->ch) { - case '`': md_analyze_backtick(ctx, i); break; - case '<': /* Pass through. */ - case '>': md_analyze_lt_gt(ctx, i, lines, n_lines); break; case '[': /* Pass through. */ case '!': /* Pass through. */ case ']': md_analyze_bracket(ctx, i); break; case '&': md_analyze_entity(ctx, i); break; case '|': md_analyze_table_cell_boundary(ctx, i); break; - case '*': md_analyze_asterisk(ctx, i); break; - case '_': md_analyze_underscore(ctx, i); break; + case '_': /* Pass through. */ + case '*': md_analyze_emph(ctx, i); break; case '~': md_analyze_tilde(ctx, i); break; case '.': /* Pass through. */ case ':': md_analyze_permissive_url_autolink(ctx, i); break; @@ -3789,11 +3808,7 @@ md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mod /* We analyze marks in few groups to handle their precedence. */ /* (1) Entities; code spans; autolinks; raw HTML. */ - md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("&`<>")); - BACKTICK_OPENERS.head = -1; - BACKTICK_OPENERS.tail = -1; - LOWERTHEN_OPENERS.head = -1; - LOWERTHEN_OPENERS.tail = -1; + md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("&")); if(table_mode) { /* (2) Analyze table cell boundaries. @@ -3827,8 +3842,18 @@ md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int mark_beg, int mark_end) { md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("*_~@:.")); - ASTERISK_OPENERS.head = -1; - ASTERISK_OPENERS.tail = -1; + ASTERISK_OPENERS_extraword_mod3_0.head = -1; + ASTERISK_OPENERS_extraword_mod3_0.tail = -1; + ASTERISK_OPENERS_extraword_mod3_1.head = -1; + ASTERISK_OPENERS_extraword_mod3_1.tail = -1; + ASTERISK_OPENERS_extraword_mod3_2.head = -1; + ASTERISK_OPENERS_extraword_mod3_2.tail = -1; + ASTERISK_OPENERS_intraword_mod3_0.head = -1; + ASTERISK_OPENERS_intraword_mod3_0.tail = -1; + ASTERISK_OPENERS_intraword_mod3_1.head = -1; + ASTERISK_OPENERS_intraword_mod3_1.tail = -1; + ASTERISK_OPENERS_intraword_mod3_2.head = -1; + ASTERISK_OPENERS_intraword_mod3_2.tail = -1; UNDERSCORE_OPENERS.head = -1; UNDERSCORE_OPENERS.tail = -1; TILDE_OPENERS.head = -1; @@ -4048,14 +4073,24 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines) break; if(text_type == MD_TEXT_CODE) { - /* Inside code spans, new lines are transformed into single - * spaces. */ + OFF tmp; + MD_ASSERT(prev_mark != NULL); MD_ASSERT(prev_mark->ch == '`' && (prev_mark->flags & MD_MARK_OPENER)); MD_ASSERT(mark->ch == '`' && (mark->flags & MD_MARK_CLOSER)); + /* Inside a code span, trailing line whitespace has to be + * outputted. */ + tmp = off; + while(off < ctx->size && ISBLANK(off)) + off++; + if(off > tmp) + MD_TEXT(MD_TEXT_CODE, STR(tmp), off-tmp); + + /* and new lines are transformed into single spaces. */ if(prev_mark->end < off && off < mark->beg) MD_TEXT(MD_TEXT_CODE, _T(" "), 1); + } else if(text_type == MD_TEXT_HTML) { /* Inside raw HTML, we output the new line verbatim, including * any trailing spaces. */ @@ -4285,6 +4320,7 @@ abort: #define MD_BLOCK_CONTAINER_CLOSER 0x02 #define MD_BLOCK_CONTAINER (MD_BLOCK_CONTAINER_OPENER | MD_BLOCK_CONTAINER_CLOSER) #define MD_BLOCK_LOOSE_LIST 0x04 +#define MD_BLOCK_SETEXT_HEADER 0x08 struct MD_BLOCK_tag { MD_BLOCKTYPE type : 8; @@ -4351,7 +4387,7 @@ md_process_verbatim_block_contents(MD_CTX* ctx, MD_TEXTTYPE text_type, const MD_ MD_ASSERT(indent >= 0); /* Output code indentation. */ - while(indent > SIZEOF_ARRAY(indent_chunk_str)) { + while(indent > (int) SIZEOF_ARRAY(indent_chunk_str)) { MD_TEXT(text_type, indent_chunk_str, indent_chunk_size); indent -= SIZEOF_ARRAY(indent_chunk_str); } @@ -4425,6 +4461,8 @@ md_setup_fenced_code_detail(MD_CTX* ctx, const MD_BLOCK* block, MD_BLOCK_CODE_DE lang_end++; MD_CHECK(md_build_attribute(ctx, STR(beg), lang_end - beg, 0, &det->lang, lang_build)); + det->fence_char = fence_ch; + abort: return ret; } @@ -4715,6 +4753,7 @@ md_consume_link_reference_definitions(MD_CTX* ctx) /* Remove complete block. */ ctx->n_block_bytes -= n * sizeof(MD_LINE); ctx->n_block_bytes -= sizeof(MD_BLOCK); + ctx->current_block = NULL; } else { /* Remove just some initial lines from the block. */ memmove(lines, lines + n, (n_lines - n) * sizeof(MD_LINE)); @@ -4737,10 +4776,30 @@ md_end_current_block(MD_CTX* ctx) /* Check whether there is a reference definition. (We do this here instead * of in md_analyze_line() because reference definition can take multiple * lines.) */ - if(ctx->current_block->type == MD_BLOCK_P) { + if(ctx->current_block->type == MD_BLOCK_P || + (ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER))) + { MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1); - if(CH(lines[0].beg) == _T('[')) + if(CH(lines[0].beg) == _T('[')) { MD_CHECK(md_consume_link_reference_definitions(ctx)); + if(ctx->current_block == NULL) + return ret; + } + } + + if(ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER)) { + int n_lines = ctx->current_block->n_lines; + + if(n_lines > 1) { + /* Get rid of the underline. */ + ctx->current_block->n_lines--; + ctx->n_block_bytes -= sizeof(MD_LINE); + } else { + /* Only the underline has left after eating the ref. defs. + * Keep the line as beginning of a new ordinary paragraph. */ + ctx->current_block->type = MD_BLOCK_P; + return 0; + } } /* Mark we are not building any block anymore. */ @@ -4809,7 +4868,7 @@ abort: ***********************/ static int -md_is_hr_line(MD_CTX* ctx, OFF beg, OFF* p_end) +md_is_hr_line(MD_CTX* ctx, OFF beg, OFF* p_end, OFF* p_killer) { OFF off = beg + 1; int n = 1; @@ -4820,12 +4879,16 @@ md_is_hr_line(MD_CTX* ctx, OFF beg, OFF* p_end) off++; } - if(n < 3) + if(n < 3) { + *p_killer = off; return FALSE; + } /* Nothing else can be present on the line. */ - if(off < ctx->size && !ISNEWLINE(off)) + if(off < ctx->size && !ISNEWLINE(off)) { + *p_killer = off; return FALSE; + } *p_end = off; return TRUE; @@ -4864,9 +4927,6 @@ md_is_setext_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_level) while(off < ctx->size && CH(off) == CH(beg)) off++; - while(off < ctx->size && CH(off) == _T(' ')) - off++; - /* Optionally, space(s) can follow. */ while(off < ctx->size && CH(off) == _T(' ')) off++; @@ -4956,11 +5016,13 @@ md_is_opening_code_fence(MD_CTX* ctx, OFF beg, OFF* p_end) while(off < ctx->size && CH(off) == _T(' ')) off++; - /* Optionally, an info string can follow. It must not contain '`'. */ - while(off < ctx->size && CH(off) != _T('`') && !ISNEWLINE(off)) + /* Optionally, an info string can follow. */ + while(off < ctx->size && !ISNEWLINE(off)) { + /* Backtick-based fence must not contain '`' in the info string. */ + if(CH(beg) == _T('`') && CH(off) == _T('`')) + return FALSE; off++; - if(off < ctx->size && !ISNEWLINE(off)) - return FALSE; + } *p_end = off; return TRUE; @@ -5027,7 +5089,7 @@ md_is_html_block_start_condition(MD_CTX* ctx, OFF beg) static const TAG h6[] = { X("h1"), X("head"), X("header"), X("hr"), X("html"), Xend }; static const TAG i6[] = { X("iframe"), Xend }; static const TAG l6[] = { X("legend"), X("li"), X("link"), Xend }; - static const TAG m6[] = { X("main"), X("menu"), X("menuitem"), X("meta"), Xend }; + static const TAG m6[] = { X("main"), X("menu"), X("menuitem"), Xend }; static const TAG n6[] = { X("nav"), X("noframes"), Xend }; static const TAG o6[] = { X("ol"), X("optgroup"), X("option"), Xend }; static const TAG p6[] = { X("p"), X("param"), Xend }; @@ -5047,7 +5109,7 @@ md_is_html_block_start_condition(MD_CTX* ctx, OFF beg) /* Check for type 1: size) { + if(off + t1[i].len <= ctx->size) { if(md_ascii_case_eq(STR(off), t1[i].name, t1[i].len)) return 1; } @@ -5328,6 +5390,9 @@ md_is_container_mark(MD_CTX* ctx, unsigned indent, OFF beg, OFF* p_end, MD_CONTA OFF off = beg; OFF max_end; + if(indent >= ctx->code_indent_offset) + return FALSE; + /* Check for block quote mark. */ if(off < ctx->size && CH(off) == _T('>')) { off++; @@ -5406,6 +5471,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, MD_CONTAINER container = { 0 }; int prev_line_has_list_loosening_effect = ctx->last_line_has_list_loosening_effect; OFF off = beg; + OFF hr_killer = 0; int ret = 0; line->indent = md_line_indentation(ctx, total_indent, off, &off); @@ -5441,356 +5507,365 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, n_parents++; } -redo: - /* Check whether we are fenced code continuation. */ - if(pivot_line->type == MD_LINE_FENCEDCODE) { - line->beg = off; - - /* We are another MD_LINE_FENCEDCODE unless we are closing fence - * which we transform into MD_LINE_BLANK. */ - if(line->indent < ctx->code_indent_offset) { - if(md_is_closing_code_fence(ctx, CH(pivot_line->beg), off, &off)) { - line->type = MD_LINE_BLANK; - ctx->last_line_has_list_loosening_effect = FALSE; - goto done; - } + if(off >= ctx->size || ISNEWLINE(off)) { + /* Blank line does not need any real indentation to be nested inside + * a list. */ + if(n_brothers + n_children == 0) { + while(n_parents < ctx->n_containers && ctx->containers[n_parents].ch != _T('>')) + n_parents++; } + } - if(off >= ctx->size || ISNEWLINE(off)) { - /* Blank line does not need any real indentation to be nested inside - * a list. */ - if(n_brothers + n_children == 0) { - while(n_parents < ctx->n_containers && ctx->containers[n_parents].ch != _T('>')) - n_parents++; + while(TRUE) { + /* Check whether we are fenced code continuation. */ + if(pivot_line->type == MD_LINE_FENCEDCODE) { + line->beg = off; + + /* We are another MD_LINE_FENCEDCODE unless we are closing fence + * which we transform into MD_LINE_BLANK. */ + if(line->indent < ctx->code_indent_offset) { + if(md_is_closing_code_fence(ctx, CH(pivot_line->beg), off, &off)) { + line->type = MD_LINE_BLANK; + ctx->last_line_has_list_loosening_effect = FALSE; + break; + } } - } - /* Change indentation accordingly to the initial code fence. */ - if(n_parents == ctx->n_containers) { - if(line->indent > pivot_line->indent) - line->indent -= pivot_line->indent; - else - line->indent = 0; + /* Change indentation accordingly to the initial code fence. */ + if(n_parents == ctx->n_containers) { + if(line->indent > pivot_line->indent) + line->indent -= pivot_line->indent; + else + line->indent = 0; - line->type = MD_LINE_FENCEDCODE; - goto done; + line->type = MD_LINE_FENCEDCODE; + break; + } } - } - /* Check whether we are HTML block continuation. */ - if(pivot_line->type == MD_LINE_HTML && ctx->html_block_type > 0) { - int html_block_type; + /* Check whether we are HTML block continuation. */ + if(pivot_line->type == MD_LINE_HTML && ctx->html_block_type > 0) { + int html_block_type; - html_block_type = md_is_html_block_end_condition(ctx, off, &off); - if(html_block_type > 0) { - MD_ASSERT(html_block_type == ctx->html_block_type); + html_block_type = md_is_html_block_end_condition(ctx, off, &off); + if(html_block_type > 0) { + MD_ASSERT(html_block_type == ctx->html_block_type); - /* Make sure this is the last line of the block. */ - ctx->html_block_type = 0; + /* Make sure this is the last line of the block. */ + ctx->html_block_type = 0; - /* Some end conditions serve as blank lines at the same time. */ - if(html_block_type == 6 || html_block_type == 7) { - line->type = MD_LINE_BLANK; - line->indent = 0; - goto done; + /* Some end conditions serve as blank lines at the same time. */ + if(html_block_type == 6 || html_block_type == 7) { + line->type = MD_LINE_BLANK; + line->indent = 0; + break; + } } - } - - if(n_parents == ctx->n_containers) { - line->type = MD_LINE_HTML; - goto done; - } - } - - /* Check for blank line. */ - if(off >= ctx->size || ISNEWLINE(off)) { - /* Blank line does not need any real indentation to be nested inside - * a list. */ - if(n_brothers + n_children == 0) { - while(n_parents < ctx->n_containers && ctx->containers[n_parents].ch != _T('>')) - n_parents++; - } - if(pivot_line->type == MD_LINE_INDENTEDCODE && n_parents == ctx->n_containers) { - line->type = MD_LINE_INDENTEDCODE; - if(line->indent > ctx->code_indent_offset) - line->indent -= ctx->code_indent_offset; - else - line->indent = 0; - ctx->last_line_has_list_loosening_effect = FALSE; - } else { - line->type = MD_LINE_BLANK; - ctx->last_line_has_list_loosening_effect = (n_parents > 0 && - n_brothers + n_children == 0 && - ctx->containers[n_parents-1].ch != _T('>')); - -#if 1 - /* See https://github.com/mity/md4c/issues/6 - * - * This ugly checking tests we are in (yet empty) list item but not - * its very first line (with the list item mark). - * - * If we are such blank line, then any following non-blank line - * which would be part of this list item actually ends the list - * because "a list item can begin with at most one blank line." - */ - if(n_parents > 0 && ctx->containers[n_parents-1].ch != _T('>') && - n_brothers + n_children == 0 && ctx->current_block == NULL && - ctx->n_block_bytes > sizeof(MD_BLOCK)) - { - MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK)); - if(top_block->type == MD_BLOCK_LI) - ctx->last_list_item_starts_with_two_blank_lines = TRUE; + if(n_parents == ctx->n_containers) { + line->type = MD_LINE_HTML; + break; } -#endif } - goto done_on_eol; - } else { -#if 1 - /* This is 2nd half of the hack. If the flag is set (that is there - * were 2nd blank line at the start of the list item) and we would also - * belonging to such list item, then interrupt the list. */ - ctx->last_line_has_list_loosening_effect = FALSE; - if(ctx->last_list_item_starts_with_two_blank_lines) { - if(n_parents > 0 && ctx->containers[n_parents-1].ch != _T('>') && - n_brothers + n_children == 0 && ctx->current_block == NULL && - ctx->n_block_bytes > sizeof(MD_BLOCK)) - { - MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK)); - if(top_block->type == MD_BLOCK_LI) - n_parents--; + + /* Check for blank line. */ + if(off >= ctx->size || ISNEWLINE(off)) { + if(pivot_line->type == MD_LINE_INDENTEDCODE && n_parents == ctx->n_containers) { + line->type = MD_LINE_INDENTEDCODE; + if(line->indent > ctx->code_indent_offset) + line->indent -= ctx->code_indent_offset; + else + line->indent = 0; + ctx->last_line_has_list_loosening_effect = FALSE; + } else { + line->type = MD_LINE_BLANK; + ctx->last_line_has_list_loosening_effect = (n_parents > 0 && + n_brothers + n_children == 0 && + ctx->containers[n_parents-1].ch != _T('>')); + + #if 1 + /* See https://github.com/mity/md4c/issues/6 + * + * This ugly checking tests we are in (yet empty) list item but not + * its very first line (with the list item mark). + * + * If we are such blank line, then any following non-blank line + * which would be part of this list item actually ends the list + * because "a list item can begin with at most one blank line." + */ + if(n_parents > 0 && ctx->containers[n_parents-1].ch != _T('>') && + n_brothers + n_children == 0 && ctx->current_block == NULL && + ctx->n_block_bytes > (int) sizeof(MD_BLOCK)) + { + MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK)); + if(top_block->type == MD_BLOCK_LI) + ctx->last_list_item_starts_with_two_blank_lines = TRUE; + } + #endif } + break; + } else { + #if 1 + /* This is 2nd half of the hack. If the flag is set (that is there + * were 2nd blank line at the start of the list item) and we would also + * belonging to such list item, then interrupt the list. */ + ctx->last_line_has_list_loosening_effect = FALSE; + if(ctx->last_list_item_starts_with_two_blank_lines) { + if(n_parents > 0 && ctx->containers[n_parents-1].ch != _T('>') && + n_brothers + n_children == 0 && ctx->current_block == NULL && + ctx->n_block_bytes > (int) sizeof(MD_BLOCK)) + { + MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK)); + if(top_block->type == MD_BLOCK_LI) + n_parents--; + } - ctx->last_list_item_starts_with_two_blank_lines = FALSE; + ctx->last_list_item_starts_with_two_blank_lines = FALSE; + } + #endif } -#endif - } - /* Check whether we are Setext underline. */ - if(line->indent < ctx->code_indent_offset && pivot_line->type == MD_LINE_TEXT - && (CH(off) == _T('=') || CH(off) == _T('-')) - && (n_parents == ctx->n_containers)) - { - unsigned level; + /* Check whether we are Setext underline. */ + if(line->indent < ctx->code_indent_offset && pivot_line->type == MD_LINE_TEXT + && (CH(off) == _T('=') || CH(off) == _T('-')) + && (n_parents == ctx->n_containers)) + { + unsigned level; - if(md_is_setext_underline(ctx, off, &off, &level)) { - line->type = MD_LINE_SETEXTUNDERLINE; - line->data = level; - goto done; + if(md_is_setext_underline(ctx, off, &off, &level)) { + line->type = MD_LINE_SETEXTUNDERLINE; + line->data = level; + break; + } } - } - /* Check for thematic break line. */ - if(line->indent < ctx->code_indent_offset && ISANYOF(off, _T("-_*"))) { - if(md_is_hr_line(ctx, off, &off)) { - line->type = MD_LINE_HR; - goto done; + /* Check for thematic break line. */ + if(line->indent < ctx->code_indent_offset && ISANYOF(off, _T("-_*")) && off >= hr_killer) { + if(md_is_hr_line(ctx, off, &off, &hr_killer)) { + line->type = MD_LINE_HR; + break; + } } - } - - /* Check for "brother" container. I.e. whether we are another list item - * in already started list. */ - if(n_parents < ctx->n_containers && n_brothers + n_children == 0) { - OFF tmp; - if(md_is_container_mark(ctx, line->indent, off, &tmp, &container) && - md_is_container_compatible(&ctx->containers[n_parents], &container)) - { - pivot_line = &md_dummy_blank_line; + /* Check for "brother" container. I.e. whether we are another list item + * in already started list. */ + if(n_parents < ctx->n_containers && n_brothers + n_children == 0) { + OFF tmp; - off = tmp; + if(md_is_container_mark(ctx, line->indent, off, &tmp, &container) && + md_is_container_compatible(&ctx->containers[n_parents], &container)) + { + pivot_line = &md_dummy_blank_line; - total_indent += container.contents_indent - container.mark_indent; - line->indent = md_line_indentation(ctx, total_indent, off, &off); - total_indent += line->indent; - line->beg = off; + off = tmp; - /* Some of the following whitespace actually still belongs to the mark. */ - if(off >= ctx->size || ISNEWLINE(off)) { - container.contents_indent++; - } else if(line->indent <= ctx->code_indent_offset) { - container.contents_indent += line->indent; - line->indent = 0; - } else { - container.contents_indent += 1; - line->indent--; - } + total_indent += container.contents_indent - container.mark_indent; + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + line->beg = off; + + /* Some of the following whitespace actually still belongs to the mark. */ + if(off >= ctx->size || ISNEWLINE(off)) { + container.contents_indent++; + } else if(line->indent <= ctx->code_indent_offset) { + container.contents_indent += line->indent; + line->indent = 0; + } else { + container.contents_indent += 1; + line->indent--; + } - ctx->containers[n_parents].mark_indent = container.mark_indent; - ctx->containers[n_parents].contents_indent = container.contents_indent; + ctx->containers[n_parents].mark_indent = container.mark_indent; + ctx->containers[n_parents].contents_indent = container.contents_indent; - n_brothers++; - goto redo; + n_brothers++; + continue; + } } - } - - /* Check for indented code. - * Note indented code block cannot interrupt a paragraph. */ - if(line->indent >= ctx->code_indent_offset && - (pivot_line->type == MD_LINE_BLANK || pivot_line->type == MD_LINE_INDENTEDCODE)) - { - line->type = MD_LINE_INDENTEDCODE; - MD_ASSERT(line->indent >= ctx->code_indent_offset); - line->indent -= ctx->code_indent_offset; - line->data = 0; - goto done; - } - /* Check for start of a new container block. */ - if(line->indent < ctx->code_indent_offset && - md_is_container_mark(ctx, line->indent, off, &off, &container)) - { - if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && - (off >= ctx->size || ISNEWLINE(off))) - { - /* Noop. List mark followed by a blank line cannot interrupt a paragraph. */ - } else if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && - (container.ch == _T('.') || container.ch == _T(')')) && container.start != 1) + /* Check for indented code. + * Note indented code block cannot interrupt a paragraph. */ + if(line->indent >= ctx->code_indent_offset && + (pivot_line->type == MD_LINE_BLANK || pivot_line->type == MD_LINE_INDENTEDCODE)) { - /* Noop. Ordered list cannot interrupt a paragraph unless the start index is 1. */ - } else { - total_indent += container.contents_indent - container.mark_indent; - line->indent = md_line_indentation(ctx, total_indent, off, &off); - total_indent += line->indent; + line->type = MD_LINE_INDENTEDCODE; + MD_ASSERT(line->indent >= ctx->code_indent_offset); + line->indent -= ctx->code_indent_offset; + line->data = 0; + break; + } - line->beg = off; - line->data = container.ch; - - /* Some of the following whitespace actually still belongs to the mark. */ - if(off >= ctx->size || ISNEWLINE(off)) { - container.contents_indent++; - } else if(line->indent <= ctx->code_indent_offset) { - container.contents_indent += line->indent; - line->indent = 0; + /* Check for start of a new container block. */ + if(line->indent < ctx->code_indent_offset && + md_is_container_mark(ctx, line->indent, off, &off, &container)) + { + if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && + (off >= ctx->size || ISNEWLINE(off))) + { + /* Noop. List mark followed by a blank line cannot interrupt a paragraph. */ + } else if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && + (container.ch == _T('.') || container.ch == _T(')')) && container.start != 1) + { + /* Noop. Ordered list cannot interrupt a paragraph unless the start index is 1. */ } else { - container.contents_indent += 1; - line->indent--; - } + total_indent += container.contents_indent - container.mark_indent; + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + + line->beg = off; + line->data = container.ch; + + /* Some of the following whitespace actually still belongs to the mark. */ + if(off >= ctx->size || ISNEWLINE(off)) { + container.contents_indent++; + } else if(line->indent <= ctx->code_indent_offset) { + container.contents_indent += line->indent; + line->indent = 0; + } else { + container.contents_indent += 1; + line->indent--; + } - if(n_brothers + n_children == 0) - pivot_line = &md_dummy_blank_line; + if(n_brothers + n_children == 0) + pivot_line = &md_dummy_blank_line; - if(n_children == 0) - MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers)); + if(n_children == 0) + MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers)); - n_children++; - MD_CHECK(md_push_container(ctx, &container)); - goto redo; + n_children++; + MD_CHECK(md_push_container(ctx, &container)); + continue; + } } - } - /* Check whether we are table continuation. */ - if(pivot_line->type == MD_LINE_TABLE && md_is_table_row(ctx, off, &off) && - n_parents == ctx->n_containers) - { - line->type = MD_LINE_TABLE; - goto done; - } + /* Check whether we are table continuation. */ + if(pivot_line->type == MD_LINE_TABLE && md_is_table_row(ctx, off, &off) && + n_parents == ctx->n_containers) + { + line->type = MD_LINE_TABLE; + break; + } - /* Check for ATX header. */ - if(line->indent < ctx->code_indent_offset && CH(off) == _T('#')) { - unsigned level; + /* Check for ATX header. */ + if(line->indent < ctx->code_indent_offset && CH(off) == _T('#')) { + unsigned level; - if(md_is_atxheader_line(ctx, off, &line->beg, &off, &level)) { - line->type = MD_LINE_ATXHEADER; - line->data = level; - goto done; + if(md_is_atxheader_line(ctx, off, &line->beg, &off, &level)) { + line->type = MD_LINE_ATXHEADER; + line->data = level; + break; + } } - } - /* Check whether we are starting code fence. */ - if(CH(off) == _T('`') || CH(off) == _T('~')) { - if(md_is_opening_code_fence(ctx, off, &off)) { - line->type = MD_LINE_FENCEDCODE; - line->data = 1; - goto done; + /* Check whether we are starting code fence. */ + if(CH(off) == _T('`') || CH(off) == _T('~')) { + if(md_is_opening_code_fence(ctx, off, &off)) { + line->type = MD_LINE_FENCEDCODE; + line->data = 1; + break; + } } - } - - /* Check for start of raw HTML block. */ - if(CH(off) == _T('<') && !(ctx->parser.flags & MD_FLAG_NOHTMLBLOCKS)) - { - ctx->html_block_type = md_is_html_block_start_condition(ctx, off); - /* HTML block type 7 cannot interrupt paragraph. */ - if(ctx->html_block_type == 7 && pivot_line->type == MD_LINE_TEXT) - ctx->html_block_type = 0; + /* Check for start of raw HTML block. */ + if(CH(off) == _T('<') && !(ctx->parser.flags & MD_FLAG_NOHTMLBLOCKS)) + { + ctx->html_block_type = md_is_html_block_start_condition(ctx, off); - if(ctx->html_block_type > 0) { - /* The line itself also may immediately close the block. */ - if(md_is_html_block_end_condition(ctx, off, &off) == ctx->html_block_type) { - /* Make sure this is the last line of the block. */ + /* HTML block type 7 cannot interrupt paragraph. */ + if(ctx->html_block_type == 7 && pivot_line->type == MD_LINE_TEXT) ctx->html_block_type = 0; - } - line->type = MD_LINE_HTML; - goto done; - } - } + if(ctx->html_block_type > 0) { + /* The line itself also may immediately close the block. */ + if(md_is_html_block_end_condition(ctx, off, &off) == ctx->html_block_type) { + /* Make sure this is the last line of the block. */ + ctx->html_block_type = 0; + } - /* Check for table underline. */ - if((ctx->parser.flags & MD_FLAG_TABLES) && pivot_line->type == MD_LINE_TEXT && - (CH(off) == _T('|') || CH(off) == _T('-') || CH(off) == _T(':')) && - n_parents == ctx->n_containers) - { - unsigned col_count; + line->type = MD_LINE_HTML; + break; + } + } - if(ctx->current_block != NULL && ctx->current_block->n_lines == 1 && - md_is_table_underline(ctx, off, &off, &col_count) && - md_is_table_row(ctx, pivot_line->beg, NULL)) + /* Check for table underline. */ + if((ctx->parser.flags & MD_FLAG_TABLES) && pivot_line->type == MD_LINE_TEXT && + (CH(off) == _T('|') || CH(off) == _T('-') || CH(off) == _T(':')) && + n_parents == ctx->n_containers) { - line->data = col_count; - line->type = MD_LINE_TABLEUNDERLINE; - goto done; - } - } + unsigned col_count; - /* By default, we are normal text line. */ - line->type = MD_LINE_TEXT; - if(pivot_line->type == MD_LINE_TEXT && n_brothers + n_children == 0) { - /* Lazy continuation. */ - n_parents = ctx->n_containers; - } + if(ctx->current_block != NULL && ctx->current_block->n_lines == 1 && + md_is_table_underline(ctx, off, &off, &col_count) && + md_is_table_row(ctx, pivot_line->beg, NULL)) + { + line->data = col_count; + line->type = MD_LINE_TABLEUNDERLINE; + break; + } + } - /* Check for task mark. */ - if((ctx->parser.flags & MD_FLAG_TASKLISTS) && n_brothers + n_children > 0 && - ISANYOF_(ctx->containers[ctx->n_containers-1].ch, _T("-+*.)"))) - { - OFF tmp = off; + /* By default, we are normal text line. */ + line->type = MD_LINE_TEXT; + if(pivot_line->type == MD_LINE_TEXT && n_brothers + n_children == 0) { + /* Lazy continuation. */ + n_parents = ctx->n_containers; + } - while(tmp < ctx->size && tmp < off + 3 && ISBLANK(tmp)) - tmp++; - if(tmp + 2 < ctx->size && CH(tmp) == _T('[') && - ISANYOF(tmp+1, _T("xX ")) && CH(tmp+2) == _T(']') && - (tmp + 3 == ctx->size || ISBLANK(tmp+3) || ISNEWLINE(tmp+3))) + /* Check for task mark. */ + if((ctx->parser.flags & MD_FLAG_TASKLISTS) && n_brothers + n_children > 0 && + ISANYOF_(ctx->containers[ctx->n_containers-1].ch, _T("-+*.)"))) { - MD_CONTAINER* task_container = (n_children > 0 ? &ctx->containers[ctx->n_containers-1] : &container); - task_container->is_task = TRUE; - task_container->task_mark_off = tmp + 1; - off = tmp + 3; - while(ISWHITESPACE(off)) - off++; - line->beg = off; + OFF tmp = off; + + while(tmp < ctx->size && tmp < off + 3 && ISBLANK(tmp)) + tmp++; + if(tmp + 2 < ctx->size && CH(tmp) == _T('[') && + ISANYOF(tmp+1, _T("xX ")) && CH(tmp+2) == _T(']') && + (tmp + 3 == ctx->size || ISBLANK(tmp+3) || ISNEWLINE(tmp+3))) + { + MD_CONTAINER* task_container = (n_children > 0 ? &ctx->containers[ctx->n_containers-1] : &container); + task_container->is_task = TRUE; + task_container->task_mark_off = tmp + 1; + off = tmp + 3; + while(ISWHITESPACE(off)) + off++; + line->beg = off; + } } + + break; } -done: /* Scan for end of the line. * - * Note this is bottleneck of this function as we itereate over (almost) - * all line contents after some initial line indentation. To optimize, we - * try to eat multiple chars in every loop iteration. - * - * (Measured ~6% performance boost of md2html with this optimization for - * normal kind of input.) + * Note this is quite a bottleneck of the parsing as we here iterate almost + * over compete document. */ - while(off + 4 < ctx->size && !ISNEWLINE(off+0) && !ISNEWLINE(off+1) - && !ISNEWLINE(off+2) && !ISNEWLINE(off+3)) - off += 4; - while(off < ctx->size && !ISNEWLINE(off)) - off++; +#if defined __linux__ && !defined MD4C_USE_UTF16 + /* Recent glibc versions have superbly optimized strcspn(), even using + * vectorization if available. */ + if(ctx->doc_ends_with_newline && off < ctx->size) { + while(TRUE) { + off += (OFF) strcspn(STR(off), "\r\n"); + + /* strcspn() can stop on zero terminator; but that can appear + * anywhere in the Markfown input... */ + if(CH(off) == _T('\0')) + off++; + else + break; + } + } else +#endif + { + /* Optimization: Use some loop unrolling. */ + while(off + 3 < ctx->size && !ISNEWLINE(off+0) && !ISNEWLINE(off+1) + && !ISNEWLINE(off+2) && !ISNEWLINE(off+3)) + off += 4; + while(off < ctx->size && !ISNEWLINE(off)) + off++; + } -done_on_eol: /* Set end of the line. */ line->end = off; @@ -5855,7 +5930,7 @@ abort: } static int -md_process_line(MD_CTX* ctx, const MD_LINE_ANALYSIS** p_pivot_line, const MD_LINE_ANALYSIS* line) +md_process_line(MD_CTX* ctx, const MD_LINE_ANALYSIS** p_pivot_line, MD_LINE_ANALYSIS* line) { const MD_LINE_ANALYSIS* pivot_line = *p_pivot_line; int ret = 0; @@ -5884,8 +5959,17 @@ md_process_line(MD_CTX* ctx, const MD_LINE_ANALYSIS** p_pivot_line, const MD_LIN MD_ASSERT(ctx->current_block != NULL); ctx->current_block->type = MD_BLOCK_H; ctx->current_block->data = line->data; + ctx->current_block->flags |= MD_BLOCK_SETEXT_HEADER; + MD_CHECK(md_add_line_into_current_block(ctx, line)); MD_CHECK(md_end_current_block(ctx)); - *p_pivot_line = &md_dummy_blank_line; + if(ctx->current_block == NULL) { + *p_pivot_line = &md_dummy_blank_line; + } else { + /* This happens if we have consumed all the body as link ref. defs. + * and downgraded the underline into start of a new paragraph block. */ + line->type = MD_LINE_TEXT; + *p_pivot_line = line; + } return 0; } @@ -6000,9 +6084,10 @@ md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userd ctx.userdata = userdata; ctx.code_indent_offset = (ctx.parser.flags & MD_FLAG_NOINDENTEDCODEBLOCKS) ? (OFF)(-1) : 4; md_build_mark_char_map(&ctx); + ctx.doc_ends_with_newline = (size > 0 && ISNEWLINE_(text[size-1])); /* Reset all unresolved opener mark chains. */ - for(i = 0; i < SIZEOF_ARRAY(ctx.mark_chains); i++) { + for(i = 0; i < (int) SIZEOF_ARRAY(ctx.mark_chains); i++) { ctx.mark_chains[i].head = -1; ctx.mark_chains[i].tail = -1; } diff --git a/src/3rdparty/md4c/md4c.h b/src/3rdparty/md4c/md4c.h index 10cba67e95..dcdadad88d 100644 --- a/src/3rdparty/md4c/md4c.h +++ b/src/3rdparty/md4c/md4c.h @@ -30,10 +30,12 @@ extern "C" { #endif -/* Magic to support UTF-16. */ #if defined MD4C_USE_UTF16 + /* Magic to support UTF-16. Not that in order to use it, you have to define + * the macro MD4C_USE_UTF16 both when building MD4C as well as when + * including this header in your code. */ #ifdef _WIN32 - #include + #include typedef WCHAR MD_CHAR; #else #error MD4C_USE_UTF16 is only supported on Windows. @@ -236,6 +238,7 @@ typedef struct MD_BLOCK_H_DETAIL { typedef struct MD_BLOCK_CODE_DETAIL { MD_ATTRIBUTE info; MD_ATTRIBUTE lang; + MD_CHAR fence_char; /* The character used for fenced code block; or zero for indented code block. */ } MD_BLOCK_CODE_DETAIL; /* Detailed info for MD_BLOCK_TH and MD_BLOCK_TD. */ diff --git a/src/3rdparty/md4c/qt_attribution.json b/src/3rdparty/md4c/qt_attribution.json index 9180ed69b5..fa0fd18853 100644 --- a/src/3rdparty/md4c/qt_attribution.json +++ b/src/3rdparty/md4c/qt_attribution.json @@ -9,7 +9,7 @@ "License": "MIT License", "LicenseId": "MIT", "LicenseFile": "LICENSE.md", - "Version": "0.3.0", - "DownloadLocation": "https://github.com/mity/md4c/releases/tag/release-0.3.0-rc", + "Version": "0.3.3", + "DownloadLocation": "https://github.com/mity/md4c/releases/tag/release-0.3.3", "Copyright": "Copyright © 2016-2019 Martin Mitáš" } -- cgit v1.2.3 From f5bfb7a8db8e9ac5b37783aa2714f54e88b2ee87 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Sun, 12 May 2019 16:24:53 +0900 Subject: Fix build without features.itemviews Change-Id: I9a7c3b2a3ad68ea76b1d6b79192b936e7cd1d44e Reviewed-by: David Faure --- src/plugins/styles/mac/qmacstyle_mac.mm | 8 ++++++++ src/widgets/styles/qcommonstyle.cpp | 5 +---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index e9f046fcfa..743713c86a 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -871,8 +871,10 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg else if (qobject_cast(widg)) ct = QStyle::CT_LineEdit; #endif +#if QT_CONFIG(itemviews) else if (qobject_cast(widg)) ct = QStyle::CT_HeaderSection; +#endif #if QT_CONFIG(menubar) else if (qobject_cast(widg)) ct = QStyle::CT_MenuBar; @@ -2846,9 +2848,11 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay; } break; +#if QT_CONFIG(itemviews) case SH_ItemView_ScrollMode: ret = QAbstractItemView::ScrollPerPixel; break; +#endif case SH_TitleBar_ShowToolTipsOnButtons: // min/max/close buttons on windows don't show tool tips ret = false; @@ -4546,6 +4550,7 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, const int controlSize = getControlSize(opt, widget); switch (sr) { +#if QT_CONFIG(itemviews) case SE_ItemViewItemText: if (const QStyleOptionViewItem *vopt = qstyleoption_cast(opt)) { int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt, widget); @@ -4555,6 +4560,7 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, rect.adjust(-fw, 0, 0, 0); } break; +#endif case SE_ToolBoxTabContents: rect = QCommonStyle::subElementRect(sr, opt, widget); break; @@ -6382,12 +6388,14 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, sz = sz.expandedTo(QSize(sz.width(), minimumSize)); } break; +#if QT_CONFIG(itemviews) case CT_ItemViewItem: if (const QStyleOptionViewItem *vopt = qstyleoption_cast(opt)) { sz = QCommonStyle::sizeFromContents(ct, vopt, csz, widget); sz.setHeight(sz.height() + 2); } break; +#endif default: sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 35b630cde2..9e701995a4 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -116,10 +116,7 @@ #include -#if QT_CONFIG(itemviews) -# include "private/qtextengine_p.h" -#endif - +#include #include QT_BEGIN_NAMESPACE -- cgit v1.2.3 From 0574d5dc8a10cb4281c6f53c3d2d3e49f2109a6a Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Wed, 29 May 2019 12:16:19 +0200 Subject: Make QCoreApplicationPrivate's destructor virtual in bootstrapped builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In a bootstrapped build QCAP does not inherit from QObjectPrivate, meaning it won't get a polymorphic destructor, causing compile errors. This is necessary in preparation to add virtuals to QCAP. The "virtual" keyword is protected to avoid further warnings by compilers or linters telling that it's unnecessary because the base class' dtor is already virtual. Change-Id: Ifbd218154f74b4f1d2f2c5a3ef1fc31970f1c24b Reviewed-by: David Faure Reviewed-by: Mårten Nordheim --- src/corelib/kernel/qcoreapplication_p.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index 14ca3efd7f..6ede5d1bc0 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -84,6 +84,11 @@ public: }; QCoreApplicationPrivate(int &aargc, char **aargv, uint flags); + + // If not inheriting from QObjectPrivate: force this class to be polymorphic +#ifdef QT_NO_QOBJECT + virtual +#endif ~QCoreApplicationPrivate(); void init(); -- cgit v1.2.3 From 0f9e48d6f4e6f4976c7dc68c70ec8f4850e79e1d Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 26 Jan 2016 14:38:54 +0100 Subject: QtWidgets: eradicate some indexed loops [needing qAsConst()] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... by replacing them with C++11 range-for loops. To avoid detaches of these mutable Qt containers, wrap the container in qAsConst(). Change-Id: I9b5c23c723be024b314a7ad873e21ad63b44b348 Reviewed-by: Mårten Nordheim --- src/widgets/dialogs/qfiledialog.cpp | 13 +++++++------ src/widgets/dialogs/qfilesystemmodel.cpp | 3 +-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index fcac12068d..2f45635298 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -3675,12 +3675,13 @@ void QFileDialogPrivate::_q_autoCompleteFileName(const QString &text) if (oldFiles.removeAll(idx) == 0) newFiles.append(idx); } - for (int i = 0; i < newFiles.count(); ++i) - select(newFiles.at(i)); - if (lineEdit()->hasFocus()) - for (int i = 0; i < oldFiles.count(); ++i) - qFileDialogUi->listView->selectionModel()->select(oldFiles.at(i), - QItemSelectionModel::Toggle | QItemSelectionModel::Rows); + for (const auto &newFile : qAsConst(newFiles)) + select(newFile); + if (lineEdit()->hasFocus()) { + auto *sm = qFileDialogUi->listView->selectionModel(); + for (const auto &oldFile : qAsConst(oldFiles)) + sm->select(oldFile, QItemSelectionModel::Toggle | QItemSelectionModel::Rows); + } } } diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index e486037e08..a778fd3a45 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -1847,8 +1847,7 @@ void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, const QV std::sort(rowsToUpdate.begin(), rowsToUpdate.end()); QString min; QString max; - for (int i = 0; i < rowsToUpdate.count(); ++i) { - QString value = rowsToUpdate.at(i); + for (const QString &value : qAsConst(rowsToUpdate)) { //##TODO is there a way to bundle signals with QString as the content of the list? /*if (min.isEmpty()) { min = value; -- cgit v1.2.3 From 90f668c79fde76ce9fb09eaf0fccb1b2cf7de7eb Mon Sep 17 00:00:00 2001 From: Kevin Funk Date: Mon, 27 May 2019 20:54:53 +0200 Subject: qtreeview.h: Fix minor typo Change-Id: I62d494c0bd784ef14a7b7c1cb3b005a7529ba43e Reviewed-by: Christian Ehrlicher --- src/widgets/itemviews/qtreeview.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/itemviews/qtreeview.h b/src/widgets/itemviews/qtreeview.h index e9cc1beedb..bb00f1df07 100644 --- a/src/widgets/itemviews/qtreeview.h +++ b/src/widgets/itemviews/qtreeview.h @@ -158,7 +158,7 @@ public Q_SLOTS: void collapse(const QModelIndex &index); void resizeColumnToContents(int column); #if QT_DEPRECATED_SINCE(5, 13) - QT_DEPRECATED_X ("Use QTreeeView::sortByColumn(int column, Qt::SortOrder order) instead") + QT_DEPRECATED_X ("Use QTreeView::sortByColumn(int column, Qt::SortOrder order) instead") void sortByColumn(int column); #endif void sortByColumn(int column, Qt::SortOrder order); -- cgit v1.2.3 From a7e9fab3e9cea03c3aaf5166f57ebfd00e7a15b0 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 27 May 2019 17:33:49 +0200 Subject: Use QtPrivate::QHashCombine in qHash(QSslError) It's the same operations as boost::hash_combine, but without explicit magic numbers. Change-Id: Id65b6f6b7be3070e4ec349ed0cc062af473a95b3 Reviewed-by: Giuseppe D'Angelo --- src/network/ssl/qsslerror.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/network/ssl/qsslerror.cpp b/src/network/ssl/qsslerror.cpp index 3e822fe852..cdc018a508 100644 --- a/src/network/ssl/qsslerror.cpp +++ b/src/network/ssl/qsslerror.cpp @@ -364,9 +364,9 @@ QSslCertificate QSslError::certificate() const */ uint qHash(const QSslError &key, uint seed) noexcept { - // 2x boost::hash_combine inlined: - seed ^= qHash(key.error()) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - seed ^= qHash(key.certificate()) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + QtPrivate::QHashCombine hash; + seed = hash(seed, key.error()); + seed = hash(seed, key.certificate()); return seed; } -- cgit v1.2.3 From 0f777a3b75cd801775b04433f52d00e426c875b3 Mon Sep 17 00:00:00 2001 From: Kevin Funk Date: Mon, 27 May 2019 17:04:42 +0200 Subject: qobject_p.h: Const-correctness fix Note: This function is being called inside GammaRay Change-Id: I4260d2b720d87eec829758cf3b86bc0593d964f2 Reviewed-by: Marc Mutz --- src/corelib/kernel/qobject_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 2fb11ecc64..e6e57b29b9 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -237,7 +237,7 @@ public: { return reinterpret_cast(this + 1)[i + 1]; } - int count() { return static_cast(allocated); } + int count() const { return static_cast(allocated); } }; -- cgit v1.2.3 From 4469e36d7203a55a4e158a50f0e9effc3f2fa3c2 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 15 May 2019 14:04:11 +0200 Subject: qhashfunctions.h: add specializations of std::hash for some Qt types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have a problem. Our types don't play well with the std unordered containers, because they do not specialize std::hash. We therefore force our users to come up with an implementation, hindering interoperability, since any two developers are unlikely to come up with compatible implementations. So combining libraries written by different developers will result in ODR violations. Now that we depend on C++11, and thus the presence of std::hash, we still face the problem that the standard does not provide us with a means to compose new hash functions out of old ones. In particular, we cannot, yet, depend on C++17's std::hash to implement std::hash, say. There's also no std::hash for std::tuple, which would allow easy composition by using std::tie(). So piggy-back on the work we have done over the years on qHash() functions, and implement the std::hash specializations for Qt types using the existing qHash() functions, with a twist: The standard allows implementations to provide means against predictable hash values. Qt has this, too, but the seed is managed by the container and passed to the qHash() function as a separate argument. The standard does not have this explicit seed, so any protection must be implicit in the normal use of std::hash. To reap whatever protection that std library has on offer, if any, we calculate a seed value by hashing int(0). This will be subject to constant folding if there's no actual seed, but will produce a value dependent on the seed if there is one. Add some tests. A question that remains is how to document the specialization. Can we have a \stdhashable QDoc macro that does everything for us? Task-number: QTBUG-33428 Change-Id: Idfe775f1661f8489587353c4b148d76611ac76f3 Reviewed-by: Mårten Nordheim Reviewed-by: Qt CI Bot --- src/corelib/tools/qhashfunctions.h | 36 ++++++++++++++++++++++ .../tools/qhashfunctions/tst_qhashfunctions.cpp | 36 ++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h index 5e714806ff..2ff3464912 100644 --- a/src/corelib/tools/qhashfunctions.h +++ b/src/corelib/tools/qhashfunctions.h @@ -45,6 +45,7 @@ #include #include // for std::accumulate +#include // for std::hash #if 0 #pragma qt_class(QHashFunctions) @@ -172,6 +173,41 @@ template inline uint qHash(const std::pair &k return seed; } +#define QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH(Class, Arguments) \ + QT_BEGIN_INCLUDE_NAMESPACE \ + namespace std { \ + template <> \ + struct hash< QT_PREPEND_NAMESPACE(Class) > { \ + using argument_type = QT_PREPEND_NAMESPACE(Class); \ + using result_type = size_t; \ + size_t operator()(Arguments s) const \ + noexcept(noexcept(QT_PREPEND_NAMESPACE(qHash)(s))) \ + { \ + /* this seeds qHash with the result of */ \ + /* std::hash applied to an int, to reap */ \ + /* any protection against predictable hash */ \ + /* values the std implementation may provide */ \ + return QT_PREPEND_NAMESPACE(qHash)(s, \ + QT_PREPEND_NAMESPACE(qHash)( \ + std::hash{}(0))); \ + } \ + }; \ + } \ + QT_END_INCLUDE_NAMESPACE \ + /*end*/ + +#define QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(Class) \ + QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH(Class, const argument_type &) +#define QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(Class) \ + QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH(Class, argument_type) + +QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QString) +QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QStringRef) +QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QStringView) +QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QLatin1String) +QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QByteArray) +QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QBitArray) + QT_END_NAMESPACE #if defined(Q_CC_MSVC) diff --git a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp index 124e3cdf00..f76f3aa0c6 100644 --- a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp +++ b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp @@ -34,6 +34,8 @@ #include #include +#include + class tst_QHashFunctions : public QObject { Q_OBJECT @@ -59,6 +61,8 @@ private Q_SLOTS: void range(); void rangeCommutative(); + void stdHash(); + void setGlobalQHashSeed(); }; @@ -281,6 +285,38 @@ void tst_QHashFunctions::rangeCommutative() (void)qHashRangeCommutative(hashables, hashables + numHashables, seed); } +void tst_QHashFunctions::stdHash() +{ + { + std::unordered_set s = {QStringLiteral("Hello"), QStringLiteral("World")}; + QCOMPARE(s.size(), 2UL); + s.insert(QStringLiteral("Hello")); + QCOMPARE(s.size(), 2UL); + } + + { + std::unordered_set s = {QStringLiteral("Hello"), QStringLiteral("World")}; + QCOMPARE(s.size(), 2UL); + s.insert(QStringLiteral("Hello")); + QCOMPARE(s.size(), 2UL); + } + + { + std::unordered_set s = {QLatin1String("Hello"), QLatin1String("World")}; + QCOMPARE(s.size(), 2UL); + s.insert(QLatin1String("Hello")); + QCOMPARE(s.size(), 2UL); + } + + { + std::unordered_set s = {QByteArrayLiteral("Hello"), QByteArrayLiteral("World")}; + QCOMPARE(s.size(), 2UL); + s.insert(QByteArray("Hello")); + QCOMPARE(s.size(), 2UL); + } + +} + void tst_QHashFunctions::setGlobalQHashSeed() { // Setter works as advertised -- cgit v1.2.3 From 8ab4d2028f971dcddd53fa0fc9313f5abe491fa2 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 14 May 2019 20:42:01 +0200 Subject: Composition example: use std::unique_ptr instead of QScopedPointer The use of a unique_ptr member requires that the destructor be out-of-line, since the payload is only forward-declared in the header file. This is good hygiene, so do it for CompositionWidget, too. Add 'explicit' and missing = nullptr to both constructors as a drive-by. Change-Id: Ied1c89864f90d3f2c13fb4e9a8bbbe2e6fd6f1d7 Reviewed-by: Giuseppe D'Angelo --- examples/widgets/painting/composition/composition.cpp | 12 ++++++++++-- examples/widgets/painting/composition/composition.h | 10 +++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/examples/widgets/painting/composition/composition.cpp b/examples/widgets/painting/composition/composition.cpp index 9bd71735a0..a220fb42fa 100644 --- a/examples/widgets/painting/composition/composition.cpp +++ b/examples/widgets/painting/composition/composition.cpp @@ -224,6 +224,10 @@ CompositionWidget::CompositionWidget(QWidget *parent) setWindowTitle(tr("Composition Modes")); } +CompositionWidget::~CompositionWidget() +{ +} + void CompositionWidget::nextMode() { @@ -265,6 +269,10 @@ CompositionRenderer::CompositionRenderer(QWidget *parent) #endif } +CompositionRenderer::~CompositionRenderer() +{ +} + QRectF rectangle_around(const QPointF &p, const QSizeF &size = QSize(250, 200)) { QRectF rect(p, size); @@ -371,7 +379,7 @@ void CompositionRenderer::paint(QPainter *painter) if (size() != m_previous_size) { m_previous_size = size(); - QPainter p(m_fbo.data()); + QPainter p(m_fbo.get()); p.setCompositionMode(QPainter::CompositionMode_Source); p.fillRect(QRect(QPoint(0, 0), size()), Qt::transparent); p.setCompositionMode(QPainter::CompositionMode_SourceOver); @@ -382,7 +390,7 @@ void CompositionRenderer::paint(QPainter *painter) painter->beginNativePainting(); { - QPainter p(m_fbo.data()); + QPainter p(m_fbo.get()); p.beginNativePainting(); m_blitter.bind(); const QRect targetRect(QPoint(0, 0), m_fbo->size()); diff --git a/examples/widgets/painting/composition/composition.h b/examples/widgets/painting/composition/composition.h index 19150e2024..52ca7919b0 100644 --- a/examples/widgets/painting/composition/composition.h +++ b/examples/widgets/painting/composition/composition.h @@ -61,6 +61,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QPushButton; class QRadioButton; @@ -71,7 +73,8 @@ class CompositionWidget : public QWidget Q_OBJECT public: - CompositionWidget(QWidget *parent); + explicit CompositionWidget(QWidget *parent = nullptr); + ~CompositionWidget(); public slots: void nextMode(); @@ -117,7 +120,8 @@ class CompositionRenderer : public ArthurFrame Q_PROPERTY(bool animation READ animationEnabled WRITE setAnimationEnabled) public: - CompositionRenderer(QWidget *parent); + explicit CompositionRenderer(QWidget *parent = nullptr); + ~CompositionRenderer(); void paint(QPainter *) override; @@ -188,7 +192,7 @@ private: int m_animationTimer; #if QT_CONFIG(opengl) - QScopedPointer m_fbo; + std::unique_ptr m_fbo; int m_pbuffer_size; // width==height==size of pbuffer uint m_base_tex; uint m_compositing_tex; -- cgit v1.2.3 From 0290525ffb2d1a017e94e5bbe24dc95adb42b8ec Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 13 May 2019 23:47:56 +0200 Subject: QStyleSheetStyle: do not bypass the base class' overrides Change-Id: Iae8e24dd6c511071724fde62277ea5054b9c5253 Reviewed-by: Friedemann Kleint Reviewed-by: David Faure --- src/widgets/styles/qstylesheetstyle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index bfc0496e8c..025e1e0044 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -3446,7 +3446,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q case CE_ToolButtonLabel: if (const QStyleOptionToolButton *btn = qstyleoption_cast(opt)) { if (rule.hasBox() || btn->features & QStyleOptionToolButton::Arrow) { - QCommonStyle::drawControl(ce, opt, p, w); + QWindowsStyle::drawControl(ce, opt, p, w); } else { QStyleOptionToolButton butOpt(*btn); rule.configurePalette(&butOpt.palette, QPalette::ButtonText, QPalette::Button); @@ -3827,7 +3827,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q if (subRule.hasDrawable()) { subRule.drawRule(p, opt->rect); - QCommonStyle::drawControl(ce, &mi, p, w); + QCommonStyle::drawControl(ce, &mi, p, w); // deliberate bypass of the base } else { if (rule.hasDrawable() && !(opt->state & QStyle::State_Selected)) { // So that the menu bar background is not hidden by the items -- cgit v1.2.3 From a4084f6bf56081ba763b86596f15f15937e5e7da Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 13 May 2016 10:19:29 +0200 Subject: QAccessibleWidgets: re-enable NRVO in childWidgets() ... for poor compilers such as GCC. Change-Id: Ifcf603657ff6242599972c21b135d7b6a0af4c35 Reviewed-by: Giuseppe D'Angelo --- src/widgets/accessible/qaccessiblewidgets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widgets/accessible/qaccessiblewidgets.cpp b/src/widgets/accessible/qaccessiblewidgets.cpp index 0d87cc486d..52c953ed3a 100644 --- a/src/widgets/accessible/qaccessiblewidgets.cpp +++ b/src/widgets/accessible/qaccessiblewidgets.cpp @@ -101,9 +101,9 @@ QString qt_accHotKey(const QString &text); QList childWidgets(const QWidget *widget) { - if (widget == 0) - return QList(); QList widgets; + if (!widget) + return widgets; for (QObject *o : widget->children()) { QWidget *w = qobject_cast(o); if (!w) -- cgit v1.2.3 From 1f6ac40ff6aa3cbdaeb4da2e8adc43985b4ea651 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 28 May 2019 15:30:48 +0200 Subject: QSharedPointer: Fix build error for cross-built tools Guard friend declaration within QT_NO_QOBJECT. Amends 28ce318fcbccb5a117ca4e55322ee1c1dd8d05d4. Fixes: QTBUG-76056 Change-Id: I14fbe5457c16e8a366fecdc0a356b68b8609848b Reviewed-by: Ulf Hermann Reviewed-by: Giuseppe D'Angelo --- src/corelib/tools/qsharedpointer_impl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index 0d1dcb051b..55f0f17c52 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -678,9 +678,11 @@ public: #else template friend class QSharedPointer; template friend class QPointer; +# ifndef QT_NO_QOBJECT template friend QWeakPointer::Value, X>::type> qWeakPointerFromVariant(const QVariant &variant); +# endif template friend QPointer qPointerFromVariant(const QVariant &variant); -- cgit v1.2.3 From 98f9d4a0297e3070e9d618ce51ee7a7547bb2d91 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 24 May 2019 14:41:20 +0200 Subject: Windows QPA: Use nullptr consistently Change-Id: I09297e34bd62359e31c483199ade1d7a0baf7195 Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowsclipboard.h | 4 ++-- src/plugins/platforms/windows/qwindowscontext.h | 4 ++-- src/plugins/platforms/windows/qwindowsdialoghelpers.h | 4 ++-- src/plugins/platforms/windows/qwindowsglcontext.h | 10 +++++----- src/plugins/platforms/windows/qwindowsinputcontext.h | 2 +- src/plugins/platforms/windows/qwindowsmime.h | 2 +- src/plugins/platforms/windows/qwindowsmousehandler.h | 2 +- src/plugins/platforms/windows/qwindowsopenglcontext.h | 4 ++-- src/plugins/platforms/windows/qwindowspointerhandler.cpp | 2 +- src/plugins/platforms/windows/qwindowstheme.h | 2 +- src/plugins/platforms/windows/qwindowsvulkaninstance.cpp | 2 +- src/plugins/platforms/windows/qwindowswindow.cpp | 10 +++++----- src/plugins/platforms/windows/qwindowswindow.h | 16 ++++++++-------- 13 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h index 469d638b89..1068de15fa 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.h +++ b/src/plugins/platforms/windows/qwindowsclipboard.h @@ -87,8 +87,8 @@ private: QWindowsClipboardRetrievalMimeData m_retrievalData; QWindowsOleDataObject *m_data = nullptr; - HWND m_clipboardViewer = 0; - HWND m_nextClipboardViewer = 0; + HWND m_clipboardViewer = nullptr; + HWND m_nextClipboardViewer = nullptr; bool m_formatListenerRegistered = false; }; diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 4908f14629..ac6e5bbb9f 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -180,11 +180,11 @@ public: QString registerWindowClass(const QWindow *w); QString registerWindowClass(QString cname, WNDPROC proc, - unsigned style = 0, HBRUSH brush = 0, + unsigned style = 0, HBRUSH brush = nullptr, bool icon = false); HWND createDummyWindow(const QString &classNameIn, const wchar_t *windowName, - WNDPROC wndProc = 0, DWORD style = WS_OVERLAPPED); + WNDPROC wndProc = nullptr, DWORD style = WS_OVERLAPPED); HDC displayContext() const; int screenDepth() const; diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h index 6099ea9ac6..1cf2e50732 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h @@ -75,7 +75,7 @@ public: QWindow *parent) override; void hide() override; - virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; } + virtual bool supportsNonModalDialog(const QWindow * /* parent */ = nullptr) const { return true; } protected: QWindowsDialogHelperBase() = default; @@ -91,7 +91,7 @@ private: void cleanupThread(); QWindowsNativeDialogBasePtr m_nativeDialog; - HWND m_ownerWindow = 0; + HWND m_ownerWindow = nullptr; int m_timerId = 0; QThread *m_thread = nullptr; }; diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index 199f8112e3..5f26d1bc8c 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -75,9 +75,9 @@ struct QOpenGLContextData QOpenGLContextData(HGLRC r, HWND h, HDC d) : renderingContext(r), hwnd(h), hdc(d) {} QOpenGLContextData() {} - HGLRC renderingContext = 0; - HWND hwnd = 0; - HDC hdc = 0; + HGLRC renderingContext = nullptr; + HWND hwnd = nullptr; + HDC hdc = nullptr; }; class QOpenGLStaticContext; @@ -89,7 +89,7 @@ struct QWindowsOpenGLContextFormat QSurfaceFormat::OpenGLContextProfile profile = QSurfaceFormat::NoProfile; int version = 0; //! majorVersion<<8 + minorVersion - QSurfaceFormat::FormatOptions options = 0; + QSurfaceFormat::FormatOptions options = nullptr; }; #ifndef QT_NO_DEBUG_STREAM @@ -222,7 +222,7 @@ private: typedef GLenum (APIENTRY *GlGetGraphicsResetStatusArbType)(); inline void releaseDCs(); - bool updateObtainedParams(HDC hdc, int *obtainedSwapInterval = 0); + bool updateObtainedParams(HDC hdc, int *obtainedSwapInterval = nullptr); QOpenGLStaticContext *m_staticContext; QOpenGLContext *m_context; diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h index a47585c29e..a97c3401a6 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.h +++ b/src/plugins/platforms/windows/qwindowsinputcontext.h @@ -58,7 +58,7 @@ class QWindowsInputContext : public QPlatformInputContext struct CompositionContext { - HWND hwnd = 0; + HWND hwnd = nullptr; QString composition; int position = 0; bool isComposing = false; diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h index 6bbbae1a0e..cc6faf7847 100644 --- a/src/plugins/platforms/windows/qwindowsmime.h +++ b/src/plugins/platforms/windows/qwindowsmime.h @@ -85,7 +85,7 @@ public: // Convenience. QVariant convertToMime(const QStringList &mimeTypes, IDataObject *pDataObj, QVariant::Type preferredType, - QString *format = 0) const; + QString *format = nullptr) const; void registerMime(QWindowsMime *mime); void unregisterMime(QWindowsMime *mime) { m_mimes.removeOne(mime); } diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h index 5fe4b09c1e..309f6004b2 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.h +++ b/src/plugins/platforms/windows/qwindowsmousehandler.h @@ -79,7 +79,7 @@ public: static Qt::MouseButtons queryMouseButtons(); QWindow *windowUnderMouse() const { return m_windowUnderMouse.data(); } - void clearWindowUnderMouse() { m_windowUnderMouse = 0; } + void clearWindowUnderMouse() { m_windowUnderMouse = nullptr; } void clearEvents(); private: diff --git a/src/plugins/platforms/windows/qwindowsopenglcontext.h b/src/plugins/platforms/windows/qwindowsopenglcontext.h index cc6d93d35e..1ad911bc69 100644 --- a/src/plugins/platforms/windows/qwindowsopenglcontext.h +++ b/src/plugins/platforms/windows/qwindowsopenglcontext.h @@ -63,7 +63,7 @@ public: // If the windowing system interface needs explicitly created window surfaces (like EGL), // reimplement these. - virtual void *createWindowSurface(void * /*nativeWindow*/, void * /*nativeConfig*/, int * /*err*/) { return 0; } + virtual void *createWindowSurface(void * /*nativeWindow*/, void * /*nativeConfig*/, int * /*err*/) { return nullptr; } virtual void destroyWindowSurface(void * /*nativeSurface*/) { } protected: @@ -82,7 +82,7 @@ public: // These should be implemented only for some winsys interfaces, for example EGL. // For others, like WGL, they are not relevant. - virtual void *nativeDisplay() const { return 0; } + virtual void *nativeDisplay() const { return nullptr; } virtual void *nativeConfig() const { return 0; } protected: diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 778170d563..36c614af34 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -480,7 +480,7 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, << " message=" << Qt::hex << msg.message << " count=" << Qt::dec << count; - Qt::TouchPointStates allStates = 0; + Qt::TouchPointStates allStates = nullptr; for (quint32 i = 0; i < count; ++i) { if (QWindowsContext::verbose > 1) diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index c132f20167..4ff9b6d57d 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -71,7 +71,7 @@ public: QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override; - QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions = 0) const override; + QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions = nullptr) const override; void windowsThemeChanged(QWindow *window); void displayChanged() { refreshIconPixmapSizes(); } diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp index 7a01483abd..812ea8193a 100644 --- a/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp +++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp @@ -81,7 +81,7 @@ bool QWindowsVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, VkSurfaceKHR QWindowsVulkanInstance::createSurface(HWND win) { - VkSurfaceKHR surface = 0; + VkSurfaceKHR surface = VK_NULL_HANDLE; if (!m_createSurface) { m_createSurface = reinterpret_cast( diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index e700e6cff4..174c63bbbd 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1303,7 +1303,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) m_cursor(new CursorHandle), m_format(aWindow->requestedFormat()) #if QT_CONFIG(vulkan) - , m_vkSurface(0) + , m_vkSurface(VK_NULL_HANDLE) #endif { QWindowsContext::instance()->addWindow(m_data.hwnd, this); @@ -1404,14 +1404,14 @@ void QWindowsWindow::destroyWindow() QVulkanInstance *inst = window()->vulkanInstance(); if (inst) static_cast(inst->handle())->destroySurface(m_vkSurface); - m_vkSurface = 0; + m_vkSurface = VK_NULL_HANDLE; } #endif #ifndef QT_NO_OPENGL if (m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) staticOpenGLContext->destroyWindowSurface(m_surface); - m_surface = 0; + m_surface = nullptr; } #endif DestroyWindow(m_data.hwnd); @@ -2943,14 +2943,14 @@ void QWindowsWindow::invalidateSurface() QVulkanInstance *inst = window()->vulkanInstance(); if (inst) static_cast(inst->handle())->destroySurface(m_vkSurface); - m_vkSurface = 0; + m_vkSurface = VK_NULL_HANDLE; } #endif #ifndef QT_NO_OPENGL if (m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) staticOpenGLContext->destroyWindowSurface(m_surface); - m_surface = 0; + m_surface = nullptr; } #endif // QT_NO_OPENGL } diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 1abe1e3531..2967f44e7d 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -106,7 +106,7 @@ struct QWindowsWindowData QRect geometry; QMargins fullFrameMargins; // Do not use directly for windows, see FrameDirty. QMargins customMargins; // User-defined, additional frame for NCCALCSIZE - HWND hwnd = 0; + HWND hwnd = nullptr; bool embedded = false; bool hasFrame = false; @@ -357,7 +357,7 @@ private: inline void setParent_sys(const QPlatformWindow *parent); inline void updateTransientParent() const; void destroyWindow(); - inline bool isDropSiteEnabled() const { return m_dropTarget != 0; } + inline bool isDropSiteEnabled() const { return m_dropTarget != nullptr; } void setDropSiteEnabled(bool enabled); void updateDropSite(bool topLevel); void handleGeometryChange(); @@ -368,7 +368,7 @@ private: mutable QWindowsWindowData m_data; QPointer m_menuBar; mutable unsigned m_flags = WithinCreate; - HDC m_hdc = 0; + HDC m_hdc = nullptr; Qt::WindowStates m_windowState = Qt::WindowNoState; qreal m_opacity = 1; #ifndef QT_NO_CURSOR @@ -378,15 +378,15 @@ private: unsigned m_savedStyle = 0; QRect m_savedFrameGeometry; const QSurfaceFormat m_format; - HICON m_iconSmall = 0; - HICON m_iconBig = 0; + HICON m_iconSmall = nullptr; + HICON m_iconBig = nullptr; void *m_surface = nullptr; static bool m_screenForGLInitialized; #if QT_CONFIG(vulkan) // note: intentionally not using void * in order to avoid breaking x86 - VkSurfaceKHR m_vkSurface = 0; + VkSurfaceKHR m_vkSurface = VK_NULL_HANDLE; #endif static bool m_borderInFullScreenDefault; }; @@ -471,11 +471,11 @@ inline void QWindowsWindow::destroyIcon() { if (m_iconBig) { DestroyIcon(m_iconBig); - m_iconBig = 0; + m_iconBig = nullptr; } if (m_iconSmall) { DestroyIcon(m_iconSmall); - m_iconSmall = 0; + m_iconSmall = nullptr; } } -- cgit v1.2.3 From b61d52f98ac35c705debb5cea9195f6f2bd2ea6c Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 24 May 2019 14:43:58 +0200 Subject: Windows QPA: Replace Q_DISABLE_COPY by Q_DISABLE_COPY_MOVE Fix clang warnings like: warning: class 'QWindowsStaticOpenGLContext' defines a default destructor, a copy constructor and a copy assignment operator but does not define a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions Change-Id: I736d20476ef407100b6ecb654d1112106e545758 Reviewed-by: Oliver Wolff --- src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h | 2 +- src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h | 2 +- src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h | 2 +- src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp | 2 +- src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h | 2 +- src/plugins/platforms/windows/qwindowsbackingstore.h | 2 +- src/plugins/platforms/windows/qwindowsclipboard.h | 2 +- src/plugins/platforms/windows/qwindowscombase.h | 2 +- src/plugins/platforms/windows/qwindowscontext.h | 2 +- src/plugins/platforms/windows/qwindowscursor.h | 2 +- src/plugins/platforms/windows/qwindowsdialoghelpers.cpp | 2 +- src/plugins/platforms/windows/qwindowsdialoghelpers.h | 2 +- src/plugins/platforms/windows/qwindowseglcontext.h | 2 +- src/plugins/platforms/windows/qwindowsglcontext.cpp | 2 +- src/plugins/platforms/windows/qwindowsglcontext.h | 2 +- src/plugins/platforms/windows/qwindowsinputcontext.h | 2 +- src/plugins/platforms/windows/qwindowsintegration.cpp | 2 +- src/plugins/platforms/windows/qwindowsintegration.h | 2 +- src/plugins/platforms/windows/qwindowskeymapper.h | 2 +- src/plugins/platforms/windows/qwindowsmime.h | 4 ++-- src/plugins/platforms/windows/qwindowsmousehandler.h | 2 +- src/plugins/platforms/windows/qwindowsopenglcontext.h | 4 ++-- src/plugins/platforms/windows/qwindowsopengltester.cpp | 2 +- src/plugins/platforms/windows/qwindowspointerhandler.h | 2 +- src/plugins/platforms/windows/qwindowssessionmanager.h | 2 +- src/plugins/platforms/windows/qwindowstabletsupport.h | 2 +- src/plugins/platforms/windows/qwindowstheme.h | 2 +- src/plugins/platforms/windows/qwindowsthreadpoolrunner.h | 2 +- src/plugins/platforms/windows/qwindowsvulkaninstance.h | 2 +- src/plugins/platforms/windows/qwindowswindow.h | 2 +- src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h | 2 +- .../platforms/windows/uiautomation/qwindowsuiagriditemprovider.h | 2 +- src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h | 2 +- .../platforms/windows/uiautomation/qwindowsuiainvokeprovider.h | 2 +- src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h | 2 +- .../platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h | 2 +- .../platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h | 2 +- .../platforms/windows/uiautomation/qwindowsuiaselectionprovider.h | 2 +- .../platforms/windows/uiautomation/qwindowsuiatableitemprovider.h | 2 +- src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h | 2 +- src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h | 2 +- .../platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h | 2 +- .../platforms/windows/uiautomation/qwindowsuiatoggleprovider.h | 2 +- src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h | 2 +- 44 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h index f72ea2b038..6d4d47e3da 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h @@ -48,7 +48,7 @@ class QWindowsDirect2DWindow; class QWindowsDirect2DBackingStore : public QPlatformBackingStore { - Q_DISABLE_COPY(QWindowsDirect2DBackingStore) + Q_DISABLE_COPY_MOVE(QWindowsDirect2DBackingStore) public: QWindowsDirect2DBackingStore(QWindow *window); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h index d8a8a49aec..8fd683106d 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h @@ -59,7 +59,7 @@ class QColor; class QWindowsDirect2DBitmap { Q_DECLARE_PRIVATE(QWindowsDirect2DBitmap) - Q_DISABLE_COPY(QWindowsDirect2DBitmap) + Q_DISABLE_COPY_MOVE(QWindowsDirect2DBitmap) public: QWindowsDirect2DBitmap(); QWindowsDirect2DBitmap(ID2D1Bitmap1 *bitmap, ID2D1DeviceContext *dc); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h index aee0eb867d..a28c674671 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h @@ -91,7 +91,7 @@ private: }; class QWindowsDirect2DDeviceContextSuspender { - Q_DISABLE_COPY(QWindowsDirect2DDeviceContextSuspender) + Q_DISABLE_COPY_MOVE(QWindowsDirect2DDeviceContextSuspender) QWindowsDirect2DDeviceContext *m_dc; public: diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index fa201c784e..1b82db0b37 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -1800,7 +1800,7 @@ void QWindowsDirect2DPaintEngine::resume() class QWindowsDirect2DPaintEngineSuspenderImpl { - Q_DISABLE_COPY(QWindowsDirect2DPaintEngineSuspenderImpl) + Q_DISABLE_COPY_MOVE(QWindowsDirect2DPaintEngineSuspenderImpl) QWindowsDirect2DPaintEngine *m_engine; bool m_active; public: diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h index 6404c60b13..f61e908bce 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h @@ -128,7 +128,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QWindowsDirect2DPaintEngine::Flags) class QWindowsDirect2DPaintEngineSuspenderPrivate; class QWindowsDirect2DPaintEngineSuspender { - Q_DISABLE_COPY(QWindowsDirect2DPaintEngineSuspender) + Q_DISABLE_COPY_MOVE(QWindowsDirect2DPaintEngineSuspender) Q_DECLARE_PRIVATE(QWindowsDirect2DPaintEngineSuspender) QScopedPointer d_ptr; public: diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h index 088ab3b257..b96c8f0e61 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.h +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -52,7 +52,7 @@ class QWindowsNativeImage; class QWindowsBackingStore : public QPlatformBackingStore { - Q_DISABLE_COPY(QWindowsBackingStore) + Q_DISABLE_COPY_MOVE(QWindowsBackingStore) public: QWindowsBackingStore(QWindow *window); ~QWindowsBackingStore() override; diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h index 1068de15fa..24a6bc908d 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.h +++ b/src/plugins/platforms/windows/qwindowsclipboard.h @@ -58,7 +58,7 @@ protected: class QWindowsClipboard : public QPlatformClipboard { - Q_DISABLE_COPY(QWindowsClipboard) + Q_DISABLE_COPY_MOVE(QWindowsClipboard) public: QWindowsClipboard(); ~QWindowsClipboard() override; diff --git a/src/plugins/platforms/windows/qwindowscombase.h b/src/plugins/platforms/windows/qwindowscombase.h index 6b25d665dc..45cba9c68b 100644 --- a/src/plugins/platforms/windows/qwindowscombase.h +++ b/src/plugins/platforms/windows/qwindowscombase.h @@ -80,7 +80,7 @@ bool qWindowsComQueryUnknownInterfaceMulti(Derived *d, REFIID id, LPVOID *iface) // Helper base class to provide IUnknown methods for COM classes (single inheritance) template class QWindowsComBase : public ComInterface { - Q_DISABLE_COPY(QWindowsComBase) + Q_DISABLE_COPY_MOVE(QWindowsComBase) public: explicit QWindowsComBase(ULONG initialRefCount = 1) : m_ref(initialRefCount) {} virtual ~QWindowsComBase() = default; diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index ac6e5bbb9f..d94ae3f73b 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -155,7 +155,7 @@ struct QWindowsShcoreDLL { class QWindowsContext { - Q_DISABLE_COPY(QWindowsContext) + Q_DISABLE_COPY_MOVE(QWindowsContext) public: enum SystemInfoFlags diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index 2e57c80def..d5c189b5ca 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -68,7 +68,7 @@ inline uint qHash(const QWindowsPixmapCursorCacheKey &k, uint seed) noexcept class CursorHandle { - Q_DISABLE_COPY(CursorHandle) + Q_DISABLE_COPY_MOVE(CursorHandle) public: explicit CursorHandle(HCURSOR hcursor = nullptr) : m_hcursor(hcursor) {} ~CursorHandle() diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index e0bd38c951..e55b8fd7b8 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -507,7 +507,7 @@ class QWindowsNativeFileDialogBase; class QWindowsNativeFileDialogEventHandler : public QWindowsComBase { - Q_DISABLE_COPY(QWindowsNativeFileDialogEventHandler) + Q_DISABLE_COPY_MOVE(QWindowsNativeFileDialogEventHandler) public: static IFileDialogEvents *create(QWindowsNativeFileDialogBase *nativeFileDialog); diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h index 1cf2e50732..f0a7ef5e90 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h @@ -64,7 +64,7 @@ namespace QWindowsDialogs template class QWindowsDialogHelperBase : public BaseClass { - Q_DISABLE_COPY(QWindowsDialogHelperBase) + Q_DISABLE_COPY_MOVE(QWindowsDialogHelperBase) public: typedef QSharedPointer QWindowsNativeDialogBasePtr; ~QWindowsDialogHelperBase() { cleanupThread(); } diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h index 8a1e1ddae8..d96e266159 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.h +++ b/src/plugins/platforms/windows/qwindowseglcontext.h @@ -109,7 +109,7 @@ private: class QWindowsEGLStaticContext : public QWindowsStaticOpenGLContext { - Q_DISABLE_COPY(QWindowsEGLStaticContext) + Q_DISABLE_COPY_MOVE(QWindowsEGLStaticContext) public: static QWindowsEGLStaticContext *create(QWindowsOpenGLTester::Renderers preferredType); diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index d534ce87cd..66dd32d05e 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -916,7 +916,7 @@ void QWindowsOpenGLContextFormat::apply(QSurfaceFormat *format) const class QOpenGLTemporaryContext { - Q_DISABLE_COPY(QOpenGLTemporaryContext) + Q_DISABLE_COPY_MOVE(QOpenGLTemporaryContext) public: QOpenGLTemporaryContext(); ~QOpenGLTemporaryContext(); diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index 5f26d1bc8c..1abe2eb390 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -134,7 +134,7 @@ private: class QOpenGLStaticContext : public QWindowsStaticOpenGLContext { - Q_DISABLE_COPY(QOpenGLStaticContext) + Q_DISABLE_COPY_MOVE(QOpenGLStaticContext) QOpenGLStaticContext(); public: enum Extensions diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h index a97c3401a6..857706bcb9 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.h +++ b/src/plugins/platforms/windows/qwindowsinputcontext.h @@ -53,7 +53,7 @@ class QWindowsWindow; class QWindowsInputContext : public QPlatformInputContext { - Q_DISABLE_COPY(QWindowsInputContext) + Q_DISABLE_COPY_MOVE(QWindowsInputContext) Q_OBJECT struct CompositionContext diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 8dd3810463..f0754e3e57 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -133,7 +133,7 @@ QT_BEGIN_NAMESPACE struct QWindowsIntegrationPrivate { - Q_DISABLE_COPY(QWindowsIntegrationPrivate) + Q_DISABLE_COPY_MOVE(QWindowsIntegrationPrivate) explicit QWindowsIntegrationPrivate(const QStringList ¶mList); ~QWindowsIntegrationPrivate(); diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 015cf79b6c..b49d21022b 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -54,7 +54,7 @@ class QWindowsStaticOpenGLContext; class QWindowsIntegration : public QPlatformIntegration { - Q_DISABLE_COPY(QWindowsIntegration) + Q_DISABLE_COPY_MOVE(QWindowsIntegration) public: enum Options { // Options to be passed on command line. FontDatabaseFreeType = 0x1, diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h index a454f0f973..b1ada1d373 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.h +++ b/src/plugins/platforms/windows/qwindowskeymapper.h @@ -71,7 +71,7 @@ struct KeyboardLayoutItem { class QWindowsKeyMapper { - Q_DISABLE_COPY(QWindowsKeyMapper) + Q_DISABLE_COPY_MOVE(QWindowsKeyMapper) public: explicit QWindowsKeyMapper(); ~QWindowsKeyMapper(); diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h index cc6faf7847..1c389e8800 100644 --- a/src/plugins/platforms/windows/qwindowsmime.h +++ b/src/plugins/platforms/windows/qwindowsmime.h @@ -53,7 +53,7 @@ class QMimeData; class QWindowsMime { - Q_DISABLE_COPY(QWindowsMime) + Q_DISABLE_COPY_MOVE(QWindowsMime) public: QWindowsMime(); virtual ~QWindowsMime(); @@ -73,7 +73,7 @@ public: class QWindowsMimeConverter { - Q_DISABLE_COPY(QWindowsMimeConverter) + Q_DISABLE_COPY_MOVE(QWindowsMimeConverter) public: QWindowsMimeConverter(); ~QWindowsMimeConverter(); diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h index 309f6004b2..1d3d1f4761 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.h +++ b/src/plugins/platforms/windows/qwindowsmousehandler.h @@ -54,7 +54,7 @@ class QTouchDevice; class QWindowsMouseHandler { - Q_DISABLE_COPY(QWindowsMouseHandler) + Q_DISABLE_COPY_MOVE(QWindowsMouseHandler) public: QWindowsMouseHandler(); diff --git a/src/plugins/platforms/windows/qwindowsopenglcontext.h b/src/plugins/platforms/windows/qwindowsopenglcontext.h index 1ad911bc69..1416a7e575 100644 --- a/src/plugins/platforms/windows/qwindowsopenglcontext.h +++ b/src/plugins/platforms/windows/qwindowsopenglcontext.h @@ -51,7 +51,7 @@ class QWindowsOpenGLContext; class QWindowsStaticOpenGLContext { - Q_DISABLE_COPY(QWindowsStaticOpenGLContext) + Q_DISABLE_COPY_MOVE(QWindowsStaticOpenGLContext) public: static QWindowsStaticOpenGLContext *create(); virtual ~QWindowsStaticOpenGLContext() = default; @@ -75,7 +75,7 @@ private: class QWindowsOpenGLContext : public QPlatformOpenGLContext { - Q_DISABLE_COPY(QWindowsOpenGLContext) + Q_DISABLE_COPY_MOVE(QWindowsOpenGLContext) public: // Returns the native context handle (e.g. HGLRC for WGL, EGLContext for EGL). virtual void *nativeContext() const = 0; diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index 35418a18e7..ff495c8290 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -83,7 +83,7 @@ static GpuDescription adapterIdentifierToGpuDescription(const D3DADAPTER_IDENTIF class QDirect3D9Handle { public: - Q_DISABLE_COPY(QDirect3D9Handle) + Q_DISABLE_COPY_MOVE(QDirect3D9Handle) QDirect3D9Handle(); ~QDirect3D9Handle(); diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index ccbb1d3939..068e804007 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -55,7 +55,7 @@ class QTouchDevice; class QWindowsPointerHandler { - Q_DISABLE_COPY(QWindowsPointerHandler) + Q_DISABLE_COPY_MOVE(QWindowsPointerHandler) public: QWindowsPointerHandler() = default; bool translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result); diff --git a/src/plugins/platforms/windows/qwindowssessionmanager.h b/src/plugins/platforms/windows/qwindowssessionmanager.h index 4c4256f2b0..0769ed1fce 100644 --- a/src/plugins/platforms/windows/qwindowssessionmanager.h +++ b/src/plugins/platforms/windows/qwindowssessionmanager.h @@ -79,7 +79,7 @@ private: bool m_blockUserInput = false; bool m_canceled = false; - Q_DISABLE_COPY(QWindowsSessionManager) + Q_DISABLE_COPY_MOVE(QWindowsSessionManager) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h index 8f97982308..6bcf3357a5 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.h +++ b/src/plugins/platforms/windows/qwindowstabletsupport.h @@ -110,7 +110,7 @@ QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t); class QWindowsTabletSupport { - Q_DISABLE_COPY(QWindowsTabletSupport) + Q_DISABLE_COPY_MOVE(QWindowsTabletSupport) explicit QWindowsTabletSupport(HWND window, HCTX context); diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 4ff9b6d57d..4e24308445 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -51,7 +51,7 @@ class QWindow; class QWindowsTheme : public QPlatformTheme { - Q_DISABLE_COPY(QWindowsTheme) + Q_DISABLE_COPY_MOVE(QWindowsTheme) public: QWindowsTheme(); ~QWindowsTheme() override; diff --git a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h index 731e4b5432..ffe2e62069 100644 --- a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h +++ b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE */ class QWindowsThreadPoolRunner { - Q_DISABLE_COPY(QWindowsThreadPoolRunner) + Q_DISABLE_COPY_MOVE(QWindowsThreadPoolRunner) #if QT_CONFIG(thread) template // nested class implementing QRunnable to execute a function. diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.h b/src/plugins/platforms/windows/qwindowsvulkaninstance.h index 3292137c39..cc7ef476d4 100644 --- a/src/plugins/platforms/windows/qwindowsvulkaninstance.h +++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.h @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE class QWindowsVulkanInstance : public QBasicPlatformVulkanInstance { - Q_DISABLE_COPY(QWindowsVulkanInstance) + Q_DISABLE_COPY_MOVE(QWindowsVulkanInstance) public: QWindowsVulkanInstance(QVulkanInstance *instance); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 2967f44e7d..7efbcf900c 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -117,7 +117,7 @@ struct QWindowsWindowData class QWindowsBaseWindow : public QPlatformWindow { - Q_DISABLE_COPY(QWindowsBaseWindow) + Q_DISABLE_COPY_MOVE(QWindowsBaseWindow) public: explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {} diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h index 9caa7d6898..a20df28e3f 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h @@ -57,7 +57,7 @@ class QAccessibleInterface; class QWindowsUiaBaseProvider : public QObject { Q_OBJECT - Q_DISABLE_COPY(QWindowsUiaBaseProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaBaseProvider) public: explicit QWindowsUiaBaseProvider(QAccessible::Id id); virtual ~QWindowsUiaBaseProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h index 3d17056d38..3244122038 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaGridItemProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaGridItemProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaGridItemProvider) public: explicit QWindowsUiaGridItemProvider(QAccessible::Id id); virtual ~QWindowsUiaGridItemProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h index b96fc1a93c..0e5f81108e 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaGridProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaGridProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaGridProvider) public: explicit QWindowsUiaGridProvider(QAccessible::Id id); virtual ~QWindowsUiaGridProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h index 5fb509c5f3..7d646894a1 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaInvokeProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaInvokeProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaInvokeProvider) public: explicit QWindowsUiaInvokeProvider(QAccessible::Id id); virtual ~QWindowsUiaInvokeProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h index df0d60f9c9..cdc239ed99 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h @@ -60,7 +60,7 @@ class QWindowsUiaMainProvider : public IRawElementProviderFragmentRoot { Q_OBJECT - Q_DISABLE_COPY(QWindowsUiaMainProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaMainProvider) public: static QWindowsUiaMainProvider *providerForAccessible(QAccessibleInterface *accessible); explicit QWindowsUiaMainProvider(QAccessibleInterface *a, int initialRefCount = 1); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h index c5e0a03ee5..fc82d3a2cc 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaRangeValueProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaRangeValueProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaRangeValueProvider) public: explicit QWindowsUiaRangeValueProvider(QAccessible::Id id); virtual ~QWindowsUiaRangeValueProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h index 1f2605188b..4b59c4e40f 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaSelectionItemProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaSelectionItemProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaSelectionItemProvider) public: explicit QWindowsUiaSelectionItemProvider(QAccessible::Id id); virtual ~QWindowsUiaSelectionItemProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h index 0376d25804..ee1044ec7a 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaSelectionProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaSelectionProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaSelectionProvider) public: explicit QWindowsUiaSelectionProvider(QAccessible::Id id); virtual ~QWindowsUiaSelectionProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h index bf4b52ee0b..9804c35f8e 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaTableItemProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaTableItemProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaTableItemProvider) public: explicit QWindowsUiaTableItemProvider(QAccessible::Id id); virtual ~QWindowsUiaTableItemProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h index 94c8ab93a7..a8b16035ec 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaTableProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaTableProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaTableProvider) public: explicit QWindowsUiaTableProvider(QAccessible::Id id); virtual ~QWindowsUiaTableProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h index a9be70fa16..ffab48b0e8 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaTextProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaTextProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaTextProvider) public: explicit QWindowsUiaTextProvider(QAccessible::Id id); ~QWindowsUiaTextProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h index 39b9069fc0..3b4ec63ceb 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaTextRangeProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaTextRangeProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaTextRangeProvider) public: explicit QWindowsUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset); virtual ~QWindowsUiaTextRangeProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h index 2bed6f7e36..892b635b41 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaToggleProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaToggleProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaToggleProvider) public: explicit QWindowsUiaToggleProvider(QAccessible::Id id); virtual ~QWindowsUiaToggleProvider(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h index 334a17e51d..3edfe7a08b 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE class QWindowsUiaValueProvider : public QWindowsUiaBaseProvider, public QWindowsComBase { - Q_DISABLE_COPY(QWindowsUiaValueProvider) + Q_DISABLE_COPY_MOVE(QWindowsUiaValueProvider) public: explicit QWindowsUiaValueProvider(QAccessible::Id id); virtual ~QWindowsUiaValueProvider(); -- cgit v1.2.3 From b75e6e00b7c41b46179b69b0f1bcfc8d497cb59b Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Sun, 26 May 2019 20:51:15 +0900 Subject: Fix gui build without feature.highdpiscaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ic206cb6fa1b9fae1db9923ef6596852e93b3cbe5 Reviewed-by: Morten Johan Sørvig --- src/gui/kernel/qhighdpiscaling_p.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h index dfc6abf5ba..91cfbcbfc7 100644 --- a/src/gui/kernel/qhighdpiscaling_p.h +++ b/src/gui/kernel/qhighdpiscaling_p.h @@ -413,6 +413,8 @@ public: static inline QPoint origin(const QPlatformScreen *) { return QPoint(); } static inline QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *) { return pos; } static inline QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *) { return pos; } + static inline QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window) { return pos; } + static inline QPoint mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window) { return pos; } static inline QDpi logicalDpi() { return QDpi(-1,-1); } }; -- cgit v1.2.3 From 341c8b9cd08c1cd863cf8581a825561a2862fce2 Mon Sep 17 00:00:00 2001 From: David Faure Date: Wed, 15 May 2019 15:28:18 +0200 Subject: QCommandLineParser: add --help-all, to show Qt options as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sample output at http://www.kdab.com/~dfaure/2019/help-all-example.txt Fixes: QTBUG-41802 Change-Id: I7a3350200761d41481fcb10ec4328e96e548d246 Reviewed-by: André Hartmann Reviewed-by: Thiago Macieira --- src/corelib/kernel/qcoreapplication.cpp | 7 +++ src/corelib/kernel/qcoreapplication.h | 1 + src/corelib/kernel/qcoreapplication_p.h | 3 + src/corelib/tools/qcommandlineparser.cpp | 46 ++++++++++----- src/gui/kernel/qguiapplication.cpp | 52 +++++++++++++++++ src/gui/kernel/qguiapplication_p.h | 1 + .../qcommandlineparser/tst_qcommandlineparser.cpp | 67 ++++++++++++++++++++-- 7 files changed, 158 insertions(+), 19 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index b70c61e351..72aaac44a6 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -226,6 +226,13 @@ bool QCoreApplicationPrivate::checkInstance(const char *function) return b; } +void QCoreApplicationPrivate::addQtOptions(QList *options) +{ + options->append(QCommandLineOption(QStringLiteral("qmljsdebugger"), + QStringLiteral("Activates the QML/JS debugger with a specified port. The value must be of format port:1234[,block]. \"block\" makes the application wait for a connection."), + QStringLiteral("value"))); +} + void QCoreApplicationPrivate::processCommandLineArguments() { int j = argc ? 1 : 0; diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index 3581970765..b7df004736 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -227,6 +227,7 @@ private: #endif friend Q_CORE_EXPORT QString qAppName(); friend class QClassFactory; + friend class QCommandLineParserPrivate; }; #ifdef QT_NO_DEPRECATED diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index 6ede5d1bc0..0b9029b5fe 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -52,6 +52,7 @@ // #include "QtCore/qcoreapplication.h" +#include "QtCore/qcommandlineoption.h" #include "QtCore/qtranslator.h" #if QT_CONFIG(settings) #include "QtCore/qsettings.h" @@ -104,6 +105,8 @@ public: static bool checkInstance(const char *method); + virtual void addQtOptions(QList *options); + #ifndef QT_NO_QOBJECT bool sendThroughApplicationEventFilters(QObject *, QEvent *); static bool sendThroughObjectEventFilters(QObject *, QEvent *); diff --git a/src/corelib/tools/qcommandlineparser.cpp b/src/corelib/tools/qcommandlineparser.cpp index 489724ac47..b62cc930cb 100644 --- a/src/corelib/tools/qcommandlineparser.cpp +++ b/src/corelib/tools/qcommandlineparser.cpp @@ -41,6 +41,7 @@ #include "qcommandlineparser.h" #include +#include #include #include #include @@ -70,11 +71,12 @@ public: bool parse(const QStringList &args); void checkParsed(const char *method); QStringList aliases(const QString &name) const; - QString helpText() const; + QString helpText(bool includeQtOptions) const; bool registerFoundOption(const QString &optionName); bool parseOptionValue(const QString &optionName, const QString &argument, QStringList::const_iterator *argumentIterator, QStringList::const_iterator argsEnd); + Q_NORETURN void showHelp(int exitCode, bool includeQtOptions); //! Error text set when parse() returns false QString errorText; @@ -419,7 +421,9 @@ QCommandLineOption QCommandLineParser::addVersionOption() /*! Adds the help option (\c{-h}, \c{--help} and \c{-?} on Windows) - This option is handled automatically by QCommandLineParser. + as well as an option \c{--help-all} to include Qt-specific options in the output. + + These options are handled automatically by QCommandLineParser. Remember to use setApplicationDescription to set the application description, which will be displayed when this option is used. @@ -436,8 +440,10 @@ QCommandLineOption QCommandLineParser::addHelpOption() << QStringLiteral("?") #endif << QStringLiteral("h") - << QStringLiteral("help"), tr("Displays this help.")); + << QStringLiteral("help"), tr("Displays help on commandline options.")); addOption(opt); + QCommandLineOption optHelpAll(QStringLiteral("help-all"), tr("Displays help including Qt specific options.")); + addOption(optHelpAll); d->builtinHelpOption = true; return opt; } @@ -581,7 +587,8 @@ static void showParserMessage(const QString &message, MessageType type) In addition to parsing the options (like parse()), this function also handles the builtin options and handles errors. - The builtin options are \c{--version} if addVersionOption was called and \c{--help} if addHelpOption was called. + The builtin options are \c{--version} if addVersionOption was called and + \c{--help} / \c{--help-all} if addHelpOption was called. When invoking one of these options, or when an error happens (for instance an unknown option was passed), the current process will then stop, using the exit() function. @@ -600,7 +607,10 @@ void QCommandLineParser::process(const QStringList &arguments) showVersion(); if (d->builtinHelpOption && isSet(QStringLiteral("help"))) - showHelp(EXIT_SUCCESS); + d->showHelp(EXIT_SUCCESS, false); + + if (d->builtinHelpOption && isSet(QStringLiteral("help-all"))) + d->showHelp(EXIT_SUCCESS, true); } /*! @@ -1033,7 +1043,12 @@ Q_NORETURN void QCommandLineParser::showVersion() */ Q_NORETURN void QCommandLineParser::showHelp(int exitCode) { - showParserMessage(d->helpText(), UsageMessage); + d->showHelp(exitCode, false); +} + +Q_NORETURN void QCommandLineParserPrivate::showHelp(int exitCode, bool includeQtOptions) +{ + showParserMessage(helpText(includeQtOptions), UsageMessage); qt_call_post_routines(); ::exit(exitCode); } @@ -1045,7 +1060,7 @@ Q_NORETURN void QCommandLineParser::showHelp(int exitCode) */ QString QCommandLineParser::helpText() const { - return d->helpText(); + return d->helpText(false); } static QString wrapText(const QString &names, int longestOptionNameString, const QString &description) @@ -1103,13 +1118,16 @@ static QString wrapText(const QString &names, int longestOptionNameString, const return text; } -QString QCommandLineParserPrivate::helpText() const +QString QCommandLineParserPrivate::helpText(bool includeQtOptions) const { const QLatin1Char nl('\n'); QString text; QString usage; usage += QCoreApplication::instance()->arguments().constFirst(); // executable name - if (!commandLineOptionList.isEmpty()) + QList options = commandLineOptionList; + if (includeQtOptions) + QCoreApplication::instance()->d_func()->addQtOptions(&options); + if (!options.isEmpty()) usage += QLatin1Char(' ') + QCommandLineParser::tr("[options]"); for (const PositionalArgumentDefinition &arg : positionalArgumentDefinitions) usage += QLatin1Char(' ') + arg.syntax; @@ -1117,12 +1135,12 @@ QString QCommandLineParserPrivate::helpText() const if (!description.isEmpty()) text += description + nl; text += nl; - if (!commandLineOptionList.isEmpty()) + if (!options.isEmpty()) text += QCommandLineParser::tr("Options:") + nl; QStringList optionNameList; - optionNameList.reserve(commandLineOptionList.size()); + optionNameList.reserve(options.size()); int longestOptionNameString = 0; - for (const QCommandLineOption &option : commandLineOptionList) { + for (const QCommandLineOption &option : qAsConst(options)) { if (option.flags() & QCommandLineOption::HiddenFromHelp) continue; const QStringList optionNames = option.names(); @@ -1141,14 +1159,14 @@ QString QCommandLineParserPrivate::helpText() const } ++longestOptionNameString; auto optionNameIterator = optionNameList.cbegin(); - for (const QCommandLineOption &option : commandLineOptionList) { + for (const QCommandLineOption &option : qAsConst(options)) { if (option.flags() & QCommandLineOption::HiddenFromHelp) continue; text += wrapText(*optionNameIterator, longestOptionNameString, option.description()); ++optionNameIterator; } if (!positionalArgumentDefinitions.isEmpty()) { - if (!commandLineOptionList.isEmpty()) + if (!options.isEmpty()) text += nl; text += QCommandLineParser::tr("Arguments:") + nl; for (const PositionalArgumentDefinition &arg : positionalArgumentDefinitions) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index d2858c5270..7799be77d2 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1306,6 +1306,58 @@ static void init_plugins(const QList &pluginList) } } +void QGuiApplicationPrivate::addQtOptions(QList *options) +{ + QCoreApplicationPrivate::addQtOptions(options); + +#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) + const QByteArray sessionType = qgetenv("XDG_SESSION_TYPE"); + const bool x11 = sessionType == "x11"; + // Technically the x11 aliases are only available if platformName is "xcb", but we can't know that here. +#else + const bool x11 = false; +#endif + + options->append(QCommandLineOption(QStringLiteral("platform"), + QGuiApplication::tr("QPA plugin. See QGuiApplication documentation for available options for each plugin."), QStringLiteral("platformName[:options]"))); + options->append(QCommandLineOption(QStringLiteral("platformpluginpath"), + QGuiApplication::tr("Path to the platform plugins."), QStringLiteral("path"))); + options->append(QCommandLineOption(QStringLiteral("platformtheme"), + QGuiApplication::tr("Platform theme."), QStringLiteral("theme"))); + options->append(QCommandLineOption(QStringLiteral("plugin"), + QGuiApplication::tr("Additional plugins to load, can be specified multiple times."), QStringLiteral("plugin"))); + options->append(QCommandLineOption(QStringLiteral("qwindowgeometry"), + QGuiApplication::tr("Window geometry for the main window, using the X11-syntax, like 100x100+50+50."), QStringLiteral("geometry"))); + options->append(QCommandLineOption(QStringLiteral("qwindowicon"), + QGuiApplication::tr("Default window icon."), QStringLiteral("icon"))); + options->append(QCommandLineOption(QStringLiteral("qwindowtitle"), + QGuiApplication::tr("Title of the first window."), QStringLiteral("title"))); + options->append(QCommandLineOption(QStringLiteral("reverse"), + QGuiApplication::tr("Sets the application's layout direction to Qt::RightToLeft (debugging helper)."))); + options->append(QCommandLineOption(QStringLiteral("session"), + QGuiApplication::tr("Restores the application from an earlier session."), QStringLiteral("session"))); + + if (x11) { + options->append(QCommandLineOption(QStringLiteral("display"), + QGuiApplication::tr("Display name, overrides $DISPLAY."), QStringLiteral("display"))); + options->append(QCommandLineOption(QStringLiteral("name"), + QGuiApplication::tr("Instance name according to ICCCM 4.1.2.5."), QStringLiteral("name"))); + options->append(QCommandLineOption(QStringLiteral("nograb"), + QGuiApplication::tr("Disable mouse grabbing (useful in debuggers)."))); + options->append(QCommandLineOption(QStringLiteral("dograb"), + QGuiApplication::tr("Force mouse grabbing (even when running in a debugger)."))); + options->append(QCommandLineOption(QStringLiteral("visual"), + QGuiApplication::tr("ID of the X11 Visual to use."), QStringLiteral("id"))); + // Not using the "QStringList names" solution for those aliases, because it makes the first column too wide + options->append(QCommandLineOption(QStringLiteral("geometry"), + QGuiApplication::tr("Alias for --windowgeometry."), QStringLiteral("geometry"))); + options->append(QCommandLineOption(QStringLiteral("icon"), + QGuiApplication::tr("Alias for --windowicon."), QStringLiteral("icon"))); + options->append(QCommandLineOption(QStringLiteral("title"), + QGuiApplication::tr("Alias for --windowtitle."), QStringLiteral("title"))); + } +} + void QGuiApplicationPrivate::createPlatformIntegration() { QHighDpiScaling::initHighDpiScaling(); diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index 361519661a..6902a99eca 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -92,6 +92,7 @@ public: virtual void notifyLayoutDirectionChange(); virtual void notifyActiveWindowChange(QWindow *previous); + void addQtOptions(QList *options) override; virtual bool shouldQuit() override; bool shouldQuitInternal(const QWindowList &processedWindows); diff --git a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp index de51c866e1..1e87c76d2f 100644 --- a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp +++ b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp @@ -76,6 +76,8 @@ private slots: void testHelpOption(); void testQuoteEscaping(); void testUnknownOption(); + void testHelpAll_data(); + void testHelpAll(); }; static char *empty_argv[] = { 0 }; @@ -542,7 +544,8 @@ void tst_QCommandLineParser::testVersionOption() static const char expectedOptionsHelp[] = "Options:\n" - " -h, --help Displays this help.\n" + " -h, --help Displays help on commandline options.\n" + " --help-all Displays help including Qt specific options.\n" " -v, --version Displays version information.\n" " --load Load file from URL.\n" " -o, --output Set output file.\n" @@ -576,8 +579,8 @@ void tst_QCommandLineParser::testHelpOption_data() " parsingMode The parsing mode to test.\n" " command The command to execute.\n"); #ifdef Q_OS_WIN - expectedOutput.replace(" -h, --help Displays this help.\n", - " -?, -h, --help Displays this help.\n"); + expectedOutput.replace(" -h, --help Displays help on commandline options.\n", + " -?, -h, --help Displays help on commandline options.\n"); expectedOutput.replace("testhelper/", "testhelper\\"); #endif @@ -625,8 +628,8 @@ void tst_QCommandLineParser::testHelpOption() "Arguments:\n" " resize Resize the object to a new size.\n"; #ifdef Q_OS_WIN - expectedResizeHelp.replace(" -h, --help Displays this help.\n", - " -?, -h, --help Displays this help.\n"); + expectedResizeHelp.replace(" -h, --help Displays help on commandline options.\n", + " -?, -h, --help Displays help on commandline options.\n"); expectedResizeHelp.replace("testhelper/", "testhelper\\"); #endif QCOMPARE(output, QString(expectedResizeHelp)); @@ -680,6 +683,60 @@ void tst_QCommandLineParser::testUnknownOption() #endif // QT_CONFIG(process) } +void tst_QCommandLineParser::testHelpAll_data() +{ + QTest::addColumn("parsingMode"); + QTest::addColumn("expectedHelpOutput"); + + QString expectedOutput = QString::fromLatin1( + "Usage: testhelper/qcommandlineparser_test_helper [options] parsingMode command\n" + "Test helper\n" + "\n") + + QString::fromLatin1(expectedOptionsHelp) + + QString::fromLatin1( + " --qmljsdebugger Activates the QML/JS debugger with a specified\n" + " port. The value must be of format\n" + " port:1234[,block]. \"block\" makes the application\n" + " wait for a connection.\n" + "\n" + "Arguments:\n" + " parsingMode The parsing mode to test.\n" + " command The command to execute.\n"); +#ifdef Q_OS_WIN + expectedOutput.replace(" -h, --help Displays help on commandline options.\n", + " -?, -h, --help Displays help on commandline options.\n"); + expectedOutput.replace("testhelper/", "testhelper\\"); +#endif + + QTest::newRow("collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << expectedOutput; + QTest::newRow("long") << QCommandLineParser::ParseAsLongOptions << expectedOutput; +} + +void tst_QCommandLineParser::testHelpAll() +{ +#if !QT_CONFIG(process) + QSKIP("This test requires QProcess support"); +#else +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) + QSKIP("Deploying executable applications to file system on Android not supported."); +#endif + + QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode); + QFETCH(QString, expectedHelpOutput); + QCoreApplication app(empty_argc, empty_argv); + QProcess process; + process.start("testhelper/qcommandlineparser_test_helper", QStringList() << QString::number(parsingMode) << "--help-all"); + QVERIFY(process.waitForFinished(5000)); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + QString output = process.readAll(); +#ifdef Q_OS_WIN + output.replace(QStringLiteral("\r\n"), QStringLiteral("\n")); +#endif + QCOMPARE(output.split('\n'), expectedHelpOutput.split('\n')); // easier to debug than the next line, on failure + QCOMPARE(output, expectedHelpOutput); +#endif // QT_CONFIG(process) +} + QTEST_APPLESS_MAIN(tst_QCommandLineParser) #include "tst_qcommandlineparser.moc" -- cgit v1.2.3 From 3b756bdcf52a33c33f5b7aa573912bb6bd70efbe Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Sun, 26 May 2019 00:28:46 +0900 Subject: Fix build without feature.label Change-Id: Ibe4d31d441ff691c4b354dde546e403653564ba4 Reviewed-by: David Faure --- src/widgets/kernel/kernel.pri | 7 +++++-- src/widgets/kernel/qtooltip.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/widgets/kernel/kernel.pri b/src/widgets/kernel/kernel.pri index c2f6e4ce75..a4b81335c5 100644 --- a/src/widgets/kernel/kernel.pri +++ b/src/widgets/kernel/kernel.pri @@ -23,7 +23,6 @@ HEADERS += \ kernel/qshortcut.h \ kernel/qsizepolicy.h \ kernel/qstackedlayout.h \ - kernel/qtooltip.h \ kernel/qwidget.h \ kernel/qwidget_p.h \ kernel/qwidgetaction.h \ @@ -51,7 +50,6 @@ SOURCES += \ kernel/qshortcut.cpp \ kernel/qsizepolicy.cpp \ kernel/qstackedlayout.cpp \ - kernel/qtooltip.cpp \ kernel/qwidget.cpp \ kernel/qwidgetaction.cpp \ kernel/qgesture.cpp \ @@ -79,6 +77,11 @@ qtConfig(formlayout) { SOURCES += kernel/qformlayout.cpp } +qtConfig(tooltip) { + HEADERS += kernel/qtooltip.h + SOURCES += kernel/qtooltip.cpp +} + qtConfig(whatsthis) { HEADERS += kernel/qwhatsthis.h SOURCES += kernel/qwhatsthis.cpp diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp index f81cb471fa..d030a28356 100644 --- a/src/widgets/kernel/qtooltip.cpp +++ b/src/widgets/kernel/qtooltip.cpp @@ -41,7 +41,6 @@ #endif #include -#include #include #include @@ -61,6 +60,7 @@ #ifndef QT_NO_TOOLTIP #include +#include #include #if 0 // Used to be included in Qt4 for Q_WS_MAC -- cgit v1.2.3 From 404bee752c5058506900c23faa9d577a38b300f1 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Thu, 28 Feb 2019 23:47:14 +0000 Subject: Add attribute to disable QSessionManager Loading a session manager can be problemtatic for system services that are always auto-activated or small DBus activated helpers which shouldn't really be restored nor gain anything from a session. The current solutions is to connect to commitDataRequest and saveStateRequest and then reset a restart hint. It's very unintuitive and somewhat wasteful given the X session manager is full of slow blocking calls. Rather than changing the behavior of QGuiApplication and handling null pointers, this patch loads the base QPlatformSessionManager that is used by QPAs that don't have a session manager. Change-Id: I976521d551549e2d56076e968c6be5421e4a9c20 Reviewed-by: Albert Astals Cid Reviewed-by: Aleix Pol Gonzalez Reviewed-by: Frederik Gladhorn --- src/corelib/global/qnamespace.h | 1 + src/corelib/global/qnamespace.qdoc | 7 +++++++ src/gui/kernel/qsessionmanager.cpp | 6 +++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 8b27c60fec..f5f7176670 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -546,6 +546,7 @@ public: AA_DontShowShortcutsInContextMenus = 28, AA_CompressTabletEvents = 29, AA_DisableWindowContextHelpButton = 30, // ### Qt 6: remove me + AA_DisableSessionManager = 31, // Add new attributes before this line AA_AttributeCount diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 12e09d44e7..45d79902c7 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -286,6 +286,13 @@ This value was added in Qt 5.10. In Qt 6, WindowContextHelpButtonHint will not be set by default. + \value AA_DisableSessionManager Disables the QSessionManager. + By default Qt will connect to a running session manager for a GUI + application on supported platforms, use of a session manager may be + redundant for system services. + This attribute must be set before QGuiApplication is constructed. + This value was added in 5.13 + The following values are deprecated or obsolete: \value AA_ImmediateWidgetCreation This attribute is no longer fully diff --git a/src/gui/kernel/qsessionmanager.cpp b/src/gui/kernel/qsessionmanager.cpp index 493a321c74..e5e9c624b2 100644 --- a/src/gui/kernel/qsessionmanager.cpp +++ b/src/gui/kernel/qsessionmanager.cpp @@ -123,7 +123,11 @@ QSessionManagerPrivate::QSessionManagerPrivate(const QString &id, const QString &key) : QObjectPrivate() { - platformSessionManager = QGuiApplicationPrivate::platformIntegration()->createPlatformSessionManager(id, key); + if (qApp->testAttribute(Qt::AA_DisableSessionManager)) { + platformSessionManager = new QPlatformSessionManager(id, key); + } else { + platformSessionManager = QGuiApplicationPrivate::platformIntegration()->createPlatformSessionManager(id, key); + } Q_ASSERT_X(platformSessionManager, "Platform session management", "No platform session management, should use the default implementation"); } -- cgit v1.2.3 From fbb2ed150585ec3aee936eba21b770a8d2b66a4d Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 14 May 2019 20:42:01 +0200 Subject: Icons example: use std::unique_ptr instead of QScopedPointer There's talk that QScopedPointer may be deprecated. Don't use it in examples anymore. Change-Id: Ia50ef66de84dae2885f71a9dd83c5909bfa253f0 Reviewed-by: Giuseppe D'Angelo --- examples/widgets/widgets/icons/mainwindow.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/widgets/widgets/icons/mainwindow.cpp b/examples/widgets/widgets/icons/mainwindow.cpp index 0cf11c978d..91e98ff896 100644 --- a/examples/widgets/widgets/icons/mainwindow.cpp +++ b/examples/widgets/widgets/icons/mainwindow.cpp @@ -55,6 +55,8 @@ #include "imagedelegate.h" #include "mainwindow.h" +#include + //! [40] enum { OtherSize = QStyle::PM_CustomBase }; //! [40] @@ -514,8 +516,8 @@ void MainWindow::checkCurrentStyle() const QList actions = styleActionGroup->actions(); for (QAction *action : actions) { const QString styleName = action->data().toString(); - QScopedPointer candidate(QStyleFactory::create(styleName)); - Q_ASSERT(!candidate.isNull()); + const std::unique_ptr candidate{QStyleFactory::create(styleName)}; + Q_ASSERT(candidate); if (candidate->metaObject()->className() == QApplication::style()->metaObject()->className()) { action->trigger(); -- cgit v1.2.3 From 5ef6e1fa546a87c1e35b11c9e8c670f8410f88b3 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 27 May 2019 16:12:17 +0200 Subject: Improve qHash(QFont) When the families member was added to QFontDef, it was included in op== and qHash(), however the seed was passed to two qHash() calls for subobjects. With xor used as the combiner, it could happen that the seed was xored out (e.g. on empty strings), leaving a slight opening for prediciable hash values. Fix by using QtPrivate::QHashCombine, which handles the seed in such a way as to avoid the issue. Change-Id: I8a3e4c2f368306446554249763695158df5ac634 Reviewed-by: Allan Sandfeld Jensen --- src/gui/text/qfont_p.h | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h index db74ab0b65..466e19e9cc 100644 --- a/src/gui/text/qfont_p.h +++ b/src/gui/text/qfont_p.h @@ -138,19 +138,20 @@ struct QFontDef inline uint qHash(const QFontDef &fd, uint seed = 0) noexcept { - return qHash(qRound64(fd.pixelSize*10000)) // use only 4 fractional digits - ^ qHash(fd.weight) - ^ qHash(fd.style) - ^ qHash(fd.stretch) - ^ qHash(fd.styleHint) - ^ qHash(fd.styleStrategy) - ^ qHash(fd.ignorePitch) - ^ qHash(fd.fixedPitch) - ^ qHash(fd.family, seed) - ^ qHash(fd.families, seed) - ^ qHash(fd.styleName) - ^ qHash(fd.hintingPreference) - ; + QtPrivate::QHashCombine hash; + seed = hash(seed, qRound64(fd.pixelSize*10000)); // use only 4 fractional digits + seed = hash(seed, fd.weight); + seed = hash(seed, fd.style); + seed = hash(seed, fd.stretch); + seed = hash(seed, fd.styleHint); + seed = hash(seed, fd.styleStrategy); + seed = hash(seed, fd.ignorePitch); + seed = hash(seed, fd.fixedPitch); + seed = hash(seed, fd.family); + seed = hash(seed, fd.families); + seed = hash(seed, fd.styleName); + seed = hash(seed, fd.hintingPreference); + return seed; } class QFontEngineData -- cgit v1.2.3 From bc6ffcd0c583919b91cd0e41e1f29ff188fc617a Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 23 May 2019 13:52:23 +0200 Subject: Torrent example: Replace the last Java-style iterator with STL ones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scope a previous iterator variable better so we can re-use 'it' as the iterator name. Change-Id: I46d239ad2d3646168408d1ef29ed74fd07bc663f Reviewed-by: Paul Wicking Reviewed-by: Mårten Nordheim --- examples/network/torrent/torrentclient.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/network/torrent/torrentclient.cpp b/examples/network/torrent/torrentclient.cpp index b4cbbb7a45..bddf3caa1a 100644 --- a/examples/network/torrent/torrentclient.cpp +++ b/examples/network/torrent/torrentclient.cpp @@ -874,8 +874,7 @@ void TorrentClient::removeClient() // Remove the client from RateController and all structures. RateController::instance()->removeSocket(client); d->connections.removeAll(client); - QMultiMap::Iterator it = d->payloads.find(client); - while (it != d->payloads.end() && it.key() == client) { + for (auto it = d->payloads.find(client); it != d->payloads.end() && it.key() == client; /*erasing*/) { TorrentPiece *piece = it.value(); piece->inProgress = false; piece->requestedBlocks.fill(false); @@ -883,9 +882,12 @@ void TorrentClient::removeClient() } // Remove pending read requests. - QMapIterator it2(d->readIds); - while (it2.findNext(client)) - d->readIds.remove(it2.key()); + for (auto it = d->readIds.begin(), end = d->readIds.end(); it != end; /*erasing*/) { + if (it.value() == client) + it = d->readIds.erase(it); + else + ++it; + } // Delete the client later. disconnect(client, SIGNAL(disconnected()), this, SLOT(removeClient())); -- cgit v1.2.3 From 4715d6db808301e986c2399785c24ec70f68f200 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 14 May 2019 20:42:01 +0200 Subject: ThreadedOpenGL example: use std::unique_ptr instead of QScopedPointer There's talk that QScopedPointer may be deprecated. Don't use it in examples anymore. Change-Id: I05a486c2a86fcc7015a9c21ed0ce9682b0c24034 Reviewed-by: Giuseppe D'Angelo --- examples/opengl/threadedqopenglwidget/main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/opengl/threadedqopenglwidget/main.cpp b/examples/opengl/threadedqopenglwidget/main.cpp index b9e491040f..983f608543 100644 --- a/examples/opengl/threadedqopenglwidget/main.cpp +++ b/examples/opengl/threadedqopenglwidget/main.cpp @@ -58,6 +58,8 @@ #include "mainwindow.h" #include "glwidget.h" +#include + static QString getGlString(QOpenGLFunctions *functions, GLenum name) { if (const GLubyte *p = functions->glGetString(name)) @@ -104,8 +106,8 @@ int main( int argc, char ** argv ) const QString toolTip = supportsThreading ? glInfo : glInfo + QStringLiteral("\ndoes not support threaded OpenGL."); topLevelGlWidget.setToolTip(toolTip); - QScopedPointer mw1; - QScopedPointer mw2; + std::unique_ptr mw1; + std::unique_ptr mw2; if (!parser.isSet(singleOption)) { if (supportsThreading) { pos += QPoint(100, 100); -- cgit v1.2.3 From dd8131e3b25a4ac60eb55022b69b374f0b9a476c Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 29 May 2019 15:16:34 +0200 Subject: QFile: share some code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pack four qWarning() calls into a separate cold function. Use qUtf16Printable(). Saves >600b in text size on optimized AMD64 Linux GCC 9.1 builds. Change-Id: Ib25ea473d1d77faaecaf8750726c83675d87279e Reviewed-by: Mårten Nordheim --- src/corelib/io/qfile.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 37de4450cc..13af113da1 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -61,6 +61,12 @@ QT_BEGIN_NAMESPACE +Q_DECL_COLD_FUNCTION +static bool file_already_open(QFile &file, const char *where = nullptr) { + qWarning("QFile::%s: File (%ls) already open", where ? where : "open", qUtf16Printable(file.fileName())); + return false; +} + //************* QFilePrivate QFilePrivate::QFilePrivate() { @@ -324,8 +330,7 @@ QFile::setFileName(const QString &name) { Q_D(QFile); if (isOpen()) { - qWarning("QFile::setFileName: File (%s) is already opened", - qPrintable(fileName())); + file_already_open(*this, "setFileName"); close(); } if(d->fileEngine) { //get a new file engine later @@ -910,10 +915,8 @@ QFile::copy(const QString &fileName, const QString &newName) bool QFile::open(OpenMode mode) { Q_D(QFile); - if (isOpen()) { - qWarning("QFile::open: File (%s) already open", qPrintable(fileName())); - return false; - } + if (isOpen()) + return file_already_open(*this); // Either Append or NewOnly implies WriteOnly if (mode & (Append | NewOnly)) mode |= WriteOnly; @@ -982,10 +985,8 @@ bool QFile::open(OpenMode mode) bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags) { Q_D(QFile); - if (isOpen()) { - qWarning("QFile::open: File (%s) already open", qPrintable(fileName())); - return false; - } + if (isOpen()) + return file_already_open(*this); // Either Append or NewOnly implies WriteOnly if (mode & (Append | NewOnly)) mode |= WriteOnly; @@ -1041,10 +1042,8 @@ bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags) bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags) { Q_D(QFile); - if (isOpen()) { - qWarning("QFile::open: File (%s) already open", qPrintable(fileName())); - return false; - } + if (isOpen()) + return file_already_open(*this); // Either Append or NewOnly implies WriteOnly if (mode & (Append | NewOnly)) mode |= WriteOnly; -- cgit v1.2.3 From 2f542dd99636bbfbf0f3fad861dfd292efe81b01 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 29 May 2019 15:09:04 +0200 Subject: Use QStringView overloads of ::toString() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are no QLatin1String overloads, so using QLatin1String as the format string produced a temporary QString. Use QStringViewLiteral instead. Change-Id: I682eb8cfaa98fdcfb491edd290460db636a98a9f Reviewed-by: Mårten Nordheim --- src/network/access/qnetworkrequest.cpp | 2 +- src/plugins/sqldrivers/psql/qsql_psql.cpp | 4 ++-- src/plugins/sqldrivers/tds/qsql_tds.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index deb0792938..ba36c75419 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -1344,7 +1344,7 @@ QDateTime QNetworkHeadersPrivate::fromHttpDate(const QByteArray &value) QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt) { - return QLocale::c().toString(dt, QLatin1String("ddd, dd MMM yyyy hh:mm:ss 'GMT'")) + return QLocale::c().toString(dt, QStringViewLiteral("ddd, dd MMM yyyy hh:mm:ss 'GMT'")) .toLatin1(); } diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index c1be91cb22..bf9424897d 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -1506,7 +1506,7 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const // this is safe since postgresql stores only the UTC value and not the timezone offset (only used // while parsing), so we have correct behavior in both case of with timezone and without tz r = QStringLiteral("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') + - QLocale::c().toString(field.value().toDateTime().toUTC(), QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz")) + + QLocale::c().toString(field.value().toDateTime().toUTC(), QStringViewLiteral("yyyy-MM-ddThh:mm:ss.zzz")) + QLatin1Char('Z') + QLatin1Char('\''); } else { r = nullStr(); @@ -1518,7 +1518,7 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const case QVariant::Time: #if QT_CONFIG(datestring) if (field.value().toTime().isValid()) { - r = QLatin1Char('\'') + field.value().toTime().toString(QLatin1String("hh:mm:ss.zzz")) + QLatin1Char('\''); + r = QLatin1Char('\'') + field.value().toTime().toString(QStringViewLiteral("hh:mm:ss.zzz")) + QLatin1Char('\''); } else #endif { diff --git a/src/plugins/sqldrivers/tds/qsql_tds.cpp b/src/plugins/sqldrivers/tds/qsql_tds.cpp index ad95b097ef..603372230d 100644 --- a/src/plugins/sqldrivers/tds/qsql_tds.cpp +++ b/src/plugins/sqldrivers/tds/qsql_tds.cpp @@ -813,7 +813,7 @@ QString QTDSDriver::formatValue(const QSqlField &field, r = QLatin1String("NULL"); else if (field.type() == QVariant::DateTime) { if (field.value().toDateTime().isValid()){ - r = field.value().toDateTime().toString(QLatin1String("yyyyMMdd hh:mm:ss")); + r = field.value().toDateTime().toString(QStringViewLiteral("yyyyMMdd hh:mm:ss")); r.prepend(QLatin1String("'")); r.append(QLatin1String("'")); } else -- cgit v1.2.3 From 6e121d81cb4ae4663d656c29a7ac590b6069e22a Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 29 May 2019 15:06:35 +0200 Subject: QPropertyAnimation: share some code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Collapse the two qWarnings() into one by just storing what is different between them. Saves more than 400b in text size on optimized AMD64 Linux GCC 9.1 builds. Change-Id: I16489d6165a550a9ad4ce6a77ca736a1d17a8c8a Reviewed-by: Mårten Nordheim --- src/corelib/animation/qpropertyanimation.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp index 271be248ec..a1baa112fc 100644 --- a/src/corelib/animation/qpropertyanimation.cpp +++ b/src/corelib/animation/qpropertyanimation.cpp @@ -277,15 +277,20 @@ void QPropertyAnimation::updateState(QAbstractAnimation::State newState, if (oldState == Stopped) { d->setDefaultStartEndValue(d->targetValue->property(d->propertyName.constData())); //let's check if we have a start value and an end value + const char *what = nullptr; if (!startValue().isValid() && (d->direction == Backward || !d->defaultStartEndValue.isValid())) { - qWarning("QPropertyAnimation::updateState (%s, %s, %s): starting an animation without start value", - d->propertyName.constData(), d->target.data()->metaObject()->className(), - qPrintable(d->target.data()->objectName())); + what = "start"; } if (!endValue().isValid() && (d->direction == Forward || !d->defaultStartEndValue.isValid())) { - qWarning("QPropertyAnimation::updateState (%s, %s, %s): starting an animation without end value", + if (what) + what = "start and end"; + else + what = "end"; + } + if (Q_UNLIKELY(what)) { + qWarning("QPropertyAnimation::updateState (%s, %s, %ls): starting an animation without %s value", d->propertyName.constData(), d->target.data()->metaObject()->className(), - qPrintable(d->target.data()->objectName())); + qUtf16Printable(d->target.data()->objectName()), what); } } } else if (hash.value(key) == this) { -- cgit v1.2.3 From 1a872e5ff2ce538960c54986e09dcb5eb8d4bd63 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 14 May 2019 20:42:01 +0200 Subject: HTTP example: use std::unique_ptr instead of QScopedPointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the QFile factory there to actually return the payload in a unique_ptr instead of falling back to a raw pointer. The use of a unique_ptr member requires that the destructor be out-of-line, since QFile is only forward-declared in the header file. This is good hygiene, so do it for ProgressDialog, too. Change-Id: Idb6ed327f9592526bb7d0d5b2cfbffe9f08f3eea Reviewed-by: Edward Welbourne Reviewed-by: Mårten Nordheim --- examples/network/http/httpwindow.cpp | 24 ++++++++++++++++-------- examples/network/http/httpwindow.h | 8 ++++++-- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/examples/network/http/httpwindow.cpp b/examples/network/http/httpwindow.cpp index 39ffb3cc87..c7bf0c0dff 100644 --- a/examples/network/http/httpwindow.cpp +++ b/examples/network/http/httpwindow.cpp @@ -48,13 +48,14 @@ ** ****************************************************************************/ +#include "httpwindow.h" + +#include "ui_authenticationdialog.h" + #include #include #include -#include "httpwindow.h" -#include "ui_authenticationdialog.h" - #if QT_CONFIG(ssl) const char defaultUrl[] = "https://www.qt.io/"; #else @@ -74,6 +75,10 @@ ProgressDialog::ProgressDialog(const QUrl &url, QWidget *parent) setMinimumSize(QSize(400, 75)); } +ProgressDialog::~ProgressDialog() +{ +} + void ProgressDialog::networkReplyProgress(qint64 bytesRead, qint64 totalBytes) { setMaximum(totalBytes); @@ -137,6 +142,10 @@ HttpWindow::HttpWindow(QWidget *parent) urlLineEdit->setFocus(); } +HttpWindow::~HttpWindow() +{ +} + void HttpWindow::startRequest(const QUrl &requestedUrl) { url = requestedUrl; @@ -204,9 +213,9 @@ void HttpWindow::downloadFile() startRequest(newUrl); } -QFile *HttpWindow::openFileForWrite(const QString &fileName) +std::unique_ptr HttpWindow::openFileForWrite(const QString &fileName) { - QScopedPointer file(new QFile(fileName)); + std::unique_ptr file(new QFile(fileName)); if (!file->open(QIODevice::WriteOnly)) { QMessageBox::information(this, tr("Error"), tr("Unable to save the file %1: %2.") @@ -214,7 +223,7 @@ QFile *HttpWindow::openFileForWrite(const QString &fileName) file->errorString())); return nullptr; } - return file.take(); + return file; } void HttpWindow::cancelDownload() @@ -231,8 +240,7 @@ void HttpWindow::httpFinished() if (file) { fi.setFile(file->fileName()); file->close(); - delete file; - file = nullptr; + file.reset(); } if (httpRequestAborted) { diff --git a/examples/network/http/httpwindow.h b/examples/network/http/httpwindow.h index 20ad2bb4da..f7bd0047de 100644 --- a/examples/network/http/httpwindow.h +++ b/examples/network/http/httpwindow.h @@ -55,6 +55,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QFile; class QLabel; @@ -72,6 +74,7 @@ class ProgressDialog : public QProgressDialog { public: explicit ProgressDialog(const QUrl &url, QWidget *parent = nullptr); + ~ProgressDialog(); public slots: void networkReplyProgress(qint64 bytesRead, qint64 totalBytes); @@ -83,6 +86,7 @@ class HttpWindow : public QDialog public: explicit HttpWindow(QWidget *parent = nullptr); + ~HttpWindow(); void startRequest(const QUrl &requestedUrl); @@ -98,7 +102,7 @@ private slots: #endif private: - QFile *openFileForWrite(const QString &fileName); + std::unique_ptr openFileForWrite(const QString &fileName); QLabel *statusLabel; QLineEdit *urlLineEdit; @@ -110,7 +114,7 @@ private: QUrl url; QNetworkAccessManager qnam; QNetworkReply *reply; - QFile *file; + std::unique_ptr file; bool httpRequestAborted; }; -- cgit v1.2.3 From b5e0bb9152d5ffd737f8cc99aa05d6625fc585c2 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 29 May 2019 15:29:23 +0200 Subject: QWindowsFileSystemWatcher: optimize qWarning() use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first two changes avoid creation of a temporary QString and QByteArray each, by realisiing that QChar is more-or-less wchar_t on Windows and so we can just use %ls to print the wchar_t array directly. In msgFindNextFailed(), remove the inline keyword and mark the function as cold (not sure this has any effect on Windows). When building the result, don't use QTextStream. Everything that is streamed is text, so just use QString::op+=. When using the result, use qUtf16Printable and %ls instead of qPrintable and %s, to avoid the creation of a temporary QByteArray. Change-Id: I09f576b894761fe342109b386c1de3532200e03c Reviewed-by: Mårten Nordheim Reviewed-by: Thiago Macieira --- src/corelib/io/qfilesystemwatcher_win.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp index aadfe7963d..81ed694d95 100644 --- a/src/corelib/io/qfilesystemwatcher_win.cpp +++ b/src/corelib/io/qfilesystemwatcher_win.cpp @@ -306,8 +306,7 @@ void QWindowsRemovableDriveListener::addPath(const QString &p) OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, // Volume requires BACKUP_SEMANTICS 0); if (volumeHandle == INVALID_HANDLE_VALUE) { - qErrnoWarning("CreateFile %s failed.", - qPrintable(QString::fromWCharArray(devicePath))); + qErrnoWarning("CreateFile %ls failed.", devicePath); return; } @@ -324,8 +323,7 @@ void QWindowsRemovableDriveListener::addPath(const QString &p) // closed. Do it here to avoid having to close/reopen in lock message handling. CloseHandle(volumeHandle); if (!re.devNotify) { - qErrnoWarning("RegisterDeviceNotification %s failed.", - qPrintable(QString::fromWCharArray(devicePath))); + qErrnoWarning("RegisterDeviceNotification %ls failed.", devicePath); return; } @@ -641,15 +639,15 @@ QWindowsFileSystemWatcherEngineThread::~QWindowsFileSystemWatcherEngineThread() } } -static inline QString msgFindNextFailed(const QWindowsFileSystemWatcherEngineThread::PathInfoHash &pathInfos) +Q_DECL_COLD_FUNCTION +static QString msgFindNextFailed(const QWindowsFileSystemWatcherEngineThread::PathInfoHash &pathInfos) { - QString result; - QTextStream str(&result); - str << "QFileSystemWatcher: FindNextChangeNotification failed for"; + QString str; + str += QLatin1String("QFileSystemWatcher: FindNextChangeNotification failed for"); for (const QWindowsFileSystemWatcherEngine::PathInfo &pathInfo : pathInfos) - str << " \"" << QDir::toNativeSeparators(pathInfo.absolutePath) << '"'; - str << ' '; - return result; + str += QLatin1String(" \"") + QDir::toNativeSeparators(pathInfo.absolutePath) + QLatin1Char('"'); + str += QLatin1Char(' '); + return str; } void QWindowsFileSystemWatcherEngineThread::run() @@ -695,7 +693,7 @@ void QWindowsFileSystemWatcherEngineThread::run() fakeRemove = true; } - qErrnoWarning(error, "%s", qPrintable(msgFindNextFailed(h))); + qErrnoWarning(error, "%ls", qUtf16Printable(msgFindNextFailed(h))); } QMutableHashIterator it(h); while (it.hasNext()) { -- cgit v1.2.3 From 9322ee7ace75562b9f667392a900f2873579e924 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 29 May 2019 17:54:38 +0200 Subject: corelib/io: use qUtf16Printable(), %ls, qErrnoWarning() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... instead of qPrintable(), %s, explicit qt_error_string(). Saves temporary QByteArray creation, and 540b in text size on optimized Linux AMD64 GCC 9.1 builds. Change-Id: Id4e861683cf05a92faf51e4a9de9eb1dec4fc84a Reviewed-by: Mårten Nordheim Reviewed-by: Thiago Macieira --- src/corelib/io/qlockfile_unix.cpp | 2 +- src/corelib/io/qprocess_unix.cpp | 7 +++---- src/corelib/io/qsavefile.cpp | 4 ++-- src/corelib/io/qsettings_win.cpp | 28 ++++++++++++++-------------- src/corelib/io/qstandardpaths_unix.cpp | 20 +++++++++++--------- src/corelib/io/qurl.cpp | 8 ++++---- 6 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index 418b7d22ba..4a12157607 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -169,7 +169,7 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys() if (qt_write_loop(fd, fileData.constData(), fileData.size()) < fileData.size()) { qt_safe_close(fd); if (!QFile::remove(fileName)) - qWarning("QLockFile: Could not remove our own lock file %s.", qPrintable(fileName)); + qWarning("QLockFile: Could not remove our own lock file %ls.", qUtf16Printable(fileName)); return QLockFile::UnknownError; // partition full } diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 7a2daa2a57..3a29a0d842 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -202,8 +202,7 @@ static int qt_create_pipe(int *pipe) qt_safe_close(pipe[1]); int pipe_ret = qt_safe_pipe(pipe); if (pipe_ret != 0) { - qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s", - pipe, qPrintable(qt_error_string(errno))); + qErrnoWarning("QProcessPrivate::createPipe: Cannot create pipe %p", pipe); } return pipe_ret; } @@ -473,7 +472,7 @@ void QProcessPrivate::startProcess() if (forkfd == -1) { // Cleanup, report error and return #if defined (QPROCESS_DEBUG) - qDebug("fork failed: %s", qPrintable(qt_error_string(lastForkErrno))); + qDebug("fork failed: %ls", qUtf16Printable(qt_error_string(lastForkErrno))); #endif q->setProcessState(QProcess::NotRunning); setErrorAndEmit(QProcess::FailedToStart, @@ -652,7 +651,7 @@ bool QProcessPrivate::writeToStdin() qDebug("QProcessPrivate::writeToStdin(), write(%p \"%s\", %lld) == %lld", data, qt_prettyDebug(data, bytesToWrite, 16).constData(), bytesToWrite, written); if (written == -1) - qDebug("QProcessPrivate::writeToStdin(), failed to write (%s)", qPrintable(qt_error_string(errno))); + qDebug("QProcessPrivate::writeToStdin(), failed to write (%ls)", qUtf16Printable(qt_error_string(errno))); #endif if (written == -1) { // If the O_NONBLOCK flag is set and If some data can be written without blocking diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp index 0cbc8c2234..bde5133cb3 100644 --- a/src/corelib/io/qsavefile.cpp +++ b/src/corelib/io/qsavefile.cpp @@ -193,7 +193,7 @@ bool QSaveFile::open(OpenMode mode) { Q_D(QSaveFile); if (isOpen()) { - qWarning("QSaveFile::open: File (%s) already open", qPrintable(fileName())); + qWarning("QSaveFile::open: File (%ls) already open", qUtf16Printable(fileName())); return false; } unsetError(); @@ -326,7 +326,7 @@ bool QSaveFile::commit() return false; if (!isOpen()) { - qWarning("QSaveFile::commit: File (%s) is not open", qPrintable(fileName())); + qWarning("QSaveFile::commit: File (%ls) is not open", qUtf16Printable(fileName())); return false; } QFileDevice::close(); // calls flush() diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp index dd3468e1f8..679212ea21 100644 --- a/src/corelib/io/qsettings_win.cpp +++ b/src/corelib/io/qsettings_win.cpp @@ -166,8 +166,8 @@ static HKEY createOrOpenKey(HKEY parentHandle, REGSAM perms, const QString &rSub if (res == ERROR_SUCCESS) return resultHandle; - //qWarning("QSettings: Failed to create subkey \"%s\": %s", - // qPrintable(rSubKey), qPrintable(qt_error_string(int(res)))); + //qErrnoWarning(int(res), "QSettings: Failed to create subkey \"%ls\"", + // qUtf16Printable(rSubKey)); return 0; } @@ -207,7 +207,7 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS &numKeys, &maxKeySize, 0, 0, 0); if (res != ERROR_SUCCESS) { - qWarning("QSettings: RegQueryInfoKey() failed: %s", qPrintable(qt_error_string(int(res)))); + qErrnoWarning(int(res), "QSettings: RegQueryInfoKey() failed"); return result; } @@ -241,7 +241,7 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS item = QString::fromWCharArray((const wchar_t *)buff.constData(), l); if (res != ERROR_SUCCESS) { - qWarning("QSettings: RegEnumValue failed: %s", qPrintable(qt_error_string(int(res)))); + qErrnoWarning(int(res), "QSettings: RegEnumValue failed"); continue; } if (item.isEmpty()) @@ -295,8 +295,8 @@ static void deleteChildGroups(HKEY parentHandle, REGSAM access = 0) // delete group itself LONG res = RegDeleteKey(parentHandle, reinterpret_cast(group.utf16())); if (res != ERROR_SUCCESS) { - qWarning("QSettings: RegDeleteKey failed on subkey \"%s\": %s", - qPrintable(group), qPrintable(qt_error_string(int(res)))); + qErrnoWarning(int(res), "QSettings: RegDeleteKey failed on subkey \"%ls\"", + qUtf16Printable(group)); return; } } @@ -596,8 +596,8 @@ QWinSettingsPrivate::~QWinSettingsPrivate() QString emptyKey; DWORD res = RegDeleteKey(writeHandle(), reinterpret_cast(emptyKey.utf16())); if (res != ERROR_SUCCESS) { - qWarning("QSettings: Failed to delete key \"%s\": %s", - qPrintable(regList.at(0).key()), qPrintable(qt_error_string(int(res)))); + qErrnoWarning(int(res), "QSettings: Failed to delete key \"%ls\"", + qUtf16Printable(regList.constFirst().key())); } } @@ -633,16 +633,16 @@ void QWinSettingsPrivate::remove(const QString &uKey) for (const QString &group : childKeys) { LONG res = RegDeleteValue(handle, reinterpret_cast(group.utf16())); if (res != ERROR_SUCCESS) { - qWarning("QSettings: RegDeleteValue failed on subkey \"%s\": %s", - qPrintable(group), qPrintable(qt_error_string(int(res)))); + qErrnoWarning(int(res), "QSettings: RegDeleteValue failed on subkey \"%ls\"", + qUtf16Printable(group)); } } } else { res = RegDeleteKey(writeHandle(), reinterpret_cast(rKey.utf16())); if (res != ERROR_SUCCESS) { - qWarning("QSettings: RegDeleteKey failed on key \"%s\": %s", - qPrintable(rKey), qPrintable(qt_error_string(int(res)))); + qErrnoWarning(int(res), "QSettings: RegDeleteKey failed on key \"%ls\"", + qUtf16Printable(rKey)); } } RegCloseKey(handle); @@ -739,8 +739,8 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value) if (res == ERROR_SUCCESS) { deleteWriteHandleOnExit = false; } else { - qWarning("QSettings: failed to set subkey \"%s\": %s", - qPrintable(rKey), qPrintable(qt_error_string(int(res)))); + qErrnoWarning(int(res), "QSettings: failed to set subkey \"%ls\"", + qUtf16Printable(rKey)); setStatus(QSettings::AccessError); } diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp index 0c276e0a56..f4f8787968 100644 --- a/src/corelib/io/qstandardpaths_unix.cpp +++ b/src/corelib/io/qstandardpaths_unix.cpp @@ -130,29 +130,31 @@ QString QStandardPaths::writableLocation(StandardLocation type) fileInfo.setFile(xdgRuntimeDir); if (!fileInfo.isDir()) { if (!QDir().mkdir(xdgRuntimeDir)) { - qWarning("QStandardPaths: error creating runtime directory %s: %s", qPrintable(xdgRuntimeDir), qPrintable(qt_error_string(errno))); + qErrnoWarning("QStandardPaths: error creating runtime directory %ls", + qUtf16Printable(xdgRuntimeDir)); return QString(); } } #ifndef Q_OS_WASM - qWarning("QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '%s'", qPrintable(xdgRuntimeDir)); + qWarning("QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '%ls'", qUtf16Printable(xdgRuntimeDir)); #endif } else { fileInfo.setFile(xdgRuntimeDir); if (!fileInfo.exists()) { - qWarning("QStandardPaths: XDG_RUNTIME_DIR points to non-existing path '%s', " - "please create it with 0700 permissions.", qPrintable(xdgRuntimeDir)); + qWarning("QStandardPaths: XDG_RUNTIME_DIR points to non-existing path '%ls', " + "please create it with 0700 permissions.", qUtf16Printable(xdgRuntimeDir)); return QString(); } if (!fileInfo.isDir()) { - qWarning("QStandardPaths: XDG_RUNTIME_DIR points to '%s' which is not a directory", - qPrintable(xdgRuntimeDir)); + qWarning("QStandardPaths: XDG_RUNTIME_DIR points to '%ls' which is not a directory", + qUtf16Printable(xdgRuntimeDir)); return QString(); } } // "The directory MUST be owned by the user" if (fileInfo.ownerId() != myUid) { - qWarning("QStandardPaths: wrong ownership on runtime directory %s, %d instead of %d", qPrintable(xdgRuntimeDir), + qWarning("QStandardPaths: wrong ownership on runtime directory %ls, %d instead of %d", + qUtf16Printable(xdgRuntimeDir), fileInfo.ownerId(), myUid); return QString(); } @@ -163,8 +165,8 @@ QString QStandardPaths::writableLocation(StandardLocation type) if (fileInfo.permissions() != wantedPerms) { QFile file(xdgRuntimeDir); if (!file.setPermissions(wantedPerms)) { - qWarning("QStandardPaths: could not set correct permissions on runtime directory %s: %s", - qPrintable(xdgRuntimeDir), qPrintable(file.errorString())); + qWarning("QStandardPaths: could not set correct permissions on runtime directory %ls: %ls", + qUtf16Printable(xdgRuntimeDir), qUtf16Printable(file.errorString())); return QString(); } } diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index b4090f710e..681a0c7ef2 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -3266,10 +3266,10 @@ QUrl QUrl::resolved(const QUrl &relative) const removeDotsFromPath(&t.d->path); #if defined(QURL_DEBUG) - qDebug("QUrl(\"%s\").resolved(\"%s\") = \"%s\"", - qPrintable(url()), - qPrintable(relative.url()), - qPrintable(t.url())); + qDebug("QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"", + qUtf16Printable(url()), + qUtf16Printable(relative.url()), + qUtf16Printable(t.url())); #endif return t; } -- cgit v1.2.3 From 41fa84c0d803324d24605d91c2bcd28f8217a4d5 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 29 May 2019 17:50:38 +0200 Subject: QDateTimeParser: use qUtf16Printable() and %ls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... instead of qPrintable() and %s. Avoids temporary QByteArrays. Saves 1.2KiB in text size on optimized Linux AMD64 GCC 9.1 builds. Change-Id: Ie626fc478667007ce9a6bc920b8d4ec0451f2cd0 Reviewed-by: Mårten Nordheim --- src/corelib/tools/qdatetimeparser.cpp | 58 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp index e1dc596d2d..728b066db1 100644 --- a/src/corelib/tools/qdatetimeparser.cpp +++ b/src/corelib/tools/qdatetimeparser.cpp @@ -77,8 +77,8 @@ int QDateTimeParser::getDigit(const QDateTime &t, int index) const { if (index < 0 || index >= sectionNodes.size()) { #if QT_CONFIG(datestring) - qWarning("QDateTimeParser::getDigit() Internal error (%s %d)", - qPrintable(t.toString()), index); + qWarning("QDateTimeParser::getDigit() Internal error (%ls %d)", + qUtf16Printable(t.toString()), index); #else qWarning("QDateTimeParser::getDigit() Internal error (%d)", index); #endif @@ -103,8 +103,8 @@ int QDateTimeParser::getDigit(const QDateTime &t, int index) const } #if QT_CONFIG(datestring) - qWarning("QDateTimeParser::getDigit() Internal error 2 (%s %d)", - qPrintable(t.toString()), index); + qWarning("QDateTimeParser::getDigit() Internal error 2 (%ls %d)", + qUtf16Printable(t.toString()), index); #else qWarning("QDateTimeParser::getDigit() Internal error 2 (%d)", index); #endif @@ -127,8 +127,8 @@ bool QDateTimeParser::setDigit(QDateTime &v, int index, int newVal) const { if (index < 0 || index >= sectionNodes.size()) { #if QT_CONFIG(datestring) - qWarning("QDateTimeParser::setDigit() Internal error (%s %d %d)", - qPrintable(v.toString()), index, newVal); + qWarning("QDateTimeParser::setDigit() Internal error (%ls %d %d)", + qUtf16Printable(v.toString()), index, newVal); #else qWarning("QDateTimeParser::setDigit() Internal error (%d %d)", index, newVal); #endif @@ -176,8 +176,8 @@ bool QDateTimeParser::setDigit(QDateTime &v, int index, int newVal) const break; case AmPmSection: hour = (newVal == 0 ? hour % 12 : (hour % 12) + 12); break; default: - qWarning("QDateTimeParser::setDigit() Internal error (%s)", - qPrintable(node.name())); + qWarning("QDateTimeParser::setDigit() Internal error (%ls)", + qUtf16Printable(node.name())); break; } @@ -238,8 +238,8 @@ int QDateTimeParser::absoluteMax(int s, const QDateTime &cur) const case AmPmSection: return 1; default: break; } - qWarning("QDateTimeParser::absoluteMax() Internal error (%s)", - qPrintable(sn.name())); + qWarning("QDateTimeParser::absoluteMax() Internal error (%ls)", + qUtf16Printable(sn.name())); return -1; } @@ -270,8 +270,8 @@ int QDateTimeParser::absoluteMin(int s) const case AmPmSection: return 0; default: break; } - qWarning("QDateTimeParser::absoluteMin() Internal error (%s, %0x)", - qPrintable(sn.name()), sn.type); + qWarning("QDateTimeParser::absoluteMin() Internal error (%ls, %0x)", + qUtf16Printable(sn.name()), sn.type); return -1; } @@ -326,7 +326,7 @@ int QDateTimeParser::sectionPos(const SectionNode &sn) const default: break; } if (sn.pos == -1) { - qWarning("QDateTimeParser::sectionPos Internal error (%s)", qPrintable(sn.name())); + qWarning("QDateTimeParser::sectionPos Internal error (%ls)", qUtf16Printable(sn.name())); return -1; } return sn.pos; @@ -733,8 +733,8 @@ QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionIndex, ParsedSection result; // initially Invalid const SectionNode &sn = sectionNode(sectionIndex); if (sn.type & Internal) { - qWarning("QDateTimeParser::parseSection Internal error (%s %d)", - qPrintable(sn.name()), sectionIndex); + qWarning("QDateTimeParser::parseSection Internal error (%ls %d)", + qUtf16Printable(sn.name()), sectionIndex); return result; } @@ -884,8 +884,8 @@ QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionIndex, } break; } default: - qWarning("QDateTimeParser::parseSection Internal error (%s %d)", - qPrintable(sn.name()), sectionIndex); + qWarning("QDateTimeParser::parseSection Internal error (%ls %d)", + qUtf16Printable(sn.name()), sectionIndex); return result; } Q_ASSERT(result.state != Invalid || result.value == -1); @@ -1199,8 +1199,8 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, case DaySection: current = &day; sect.value = qMax(1, sect.value); break; case AmPmSection: current = &m; break; default: - qWarning("QDateTimeParser::parse Internal error (%s)", - qPrintable(sn.name())); + qWarning("QDateTimeParser::parse Internal error (%ls)", + qUtf16Printable(sn.name())); break; } @@ -1390,8 +1390,8 @@ QDateTimeParser::parse(QString input, int position, const QDateTime &defaultValu if (context != FromString && scan.value < minimum) { const QLatin1Char space(' '); if (scan.value >= minimum) - qWarning("QDateTimeParser::parse Internal error 3 (%s %s)", - qPrintable(scan.value.toString()), qPrintable(minimum.toString())); + qWarning("QDateTimeParser::parse Internal error 3 (%ls %ls)", + qUtf16Printable(scan.value.toString()), qUtf16Printable(minimum.toString())); bool done = false; scan.state = Invalid; @@ -1473,8 +1473,8 @@ QDateTimeParser::parse(QString input, int position, const QDateTime &defaultValu const int min = getDigit(minimum, i); if (min == -1) { - qWarning("QDateTimeParser::parse Internal error 4 (%s)", - qPrintable(sn.name())); + qWarning("QDateTimeParser::parse Internal error 4 (%ls)", + qUtf16Printable(sn.name())); scan.state = Invalid; done = true; break; @@ -1772,8 +1772,8 @@ int QDateTimeParser::SectionNode::maxChange() const case YearSection: return 9999 * 365; case YearSection2Digits: return 100 * 365; default: - qWarning("QDateTimeParser::maxChange() Internal error (%s)", - qPrintable(name())); + qWarning("QDateTimeParser::maxChange() Internal error (%ls)", + qUtf16Printable(name())); } return -1; @@ -1821,8 +1821,8 @@ QDateTimeParser::FieldInfo QDateTimeParser::fieldInfo(int index) const case TimeZoneSection: break; default: - qWarning("QDateTimeParser::fieldInfo Internal error 2 (%d %s %d)", - index, qPrintable(sn.name()), sn.count); + qWarning("QDateTimeParser::fieldInfo Internal error 2 (%d %ls %d)", + index, qUtf16Printable(sn.name()), sn.count); break; } return ret; @@ -1845,8 +1845,8 @@ QString QDateTimeParser::SectionNode::format() const case YearSection2Digits: case YearSection: fillChar = QLatin1Char('y'); break; default: - qWarning("QDateTimeParser::sectionFormat Internal error (%s)", - qPrintable(name(type))); + qWarning("QDateTimeParser::sectionFormat Internal error (%ls)", + qUtf16Printable(name(type))); return QString(); } if (fillChar.isNull()) { -- cgit v1.2.3 From 090085e1040110ca6ae09956db8bf8e69a268eef Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 29 May 2019 18:06:50 +0200 Subject: corelib/tools: use qUtf16Printable() and %ls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... instead of qPrintable() and %s. Saves temporary QByteArray creation. Change-Id: Idd46c99a5da731e29c6d237dc914e256ac7b3fbd Reviewed-by: Mårten Nordheim Reviewed-by: Thiago Macieira --- src/corelib/tools/qcommandlineparser.cpp | 8 ++++---- src/corelib/tools/qhash.cpp | 2 +- src/corelib/tools/qlocale_mac.mm | 4 ++-- src/corelib/tools/qregularexpression.cpp | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/corelib/tools/qcommandlineparser.cpp b/src/corelib/tools/qcommandlineparser.cpp index b62cc930cb..48501f5271 100644 --- a/src/corelib/tools/qcommandlineparser.cpp +++ b/src/corelib/tools/qcommandlineparser.cpp @@ -132,7 +132,7 @@ QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const { const NameHash_t::const_iterator it = nameHash.constFind(optionName); if (it == nameHash.cend()) { - qWarning("QCommandLineParser: option not defined: \"%s\"", qPrintable(optionName)); + qWarning("QCommandLineParser: option not defined: \"%ls\"", qUtf16Printable(optionName)); return QStringList(); } return commandLineOptionList.at(*it).names(); @@ -560,9 +560,9 @@ static void showParserMessage(const QString &message, MessageType type) { #if defined(Q_OS_WINRT) if (type == UsageMessage) - qInfo(qPrintable(message)); + qInfo("%ls", qUtf16Printable(message)); else - qCritical(qPrintable(message)); + qCritical("%ls", qUtf16Printable(message)); return; #elif defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED) if (displayMessageBox()) { @@ -898,7 +898,7 @@ QStringList QCommandLineParser::values(const QString &optionName) const return values; } - qWarning("QCommandLineParser: option not defined: \"%s\"", qPrintable(optionName)); + qWarning("QCommandLineParser: option not defined: \"%ls\"", qUtf16Printable(optionName)); return QStringList(); } diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 5c7e535c30..85a3456d71 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -709,7 +709,7 @@ void QHashData::dump() } n = n->next; } - qDebug("%s", qPrintable(line)); + qDebug("%ls", qUtf16Printable(line)); } } } diff --git a/src/corelib/tools/qlocale_mac.mm b/src/corelib/tools/qlocale_mac.mm index 6c721480f3..9719278426 100644 --- a/src/corelib/tools/qlocale_mac.mm +++ b/src/corelib/tools/qlocale_mac.mm @@ -489,8 +489,8 @@ QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const } else if (typeId == CFStringGetTypeID()) { result = QStringList(QString::fromCFString(languages.as())); } else { - qWarning("QLocale::uiLanguages(): CFPreferencesCopyValue returned unhandled type \"%s\"; please report to http://bugreports.qt.io", - qPrintable(QString::fromCFString(CFCopyTypeIDDescription(typeId)))); + qWarning("QLocale::uiLanguages(): CFPreferencesCopyValue returned unhandled type \"%ls\"; please report to http://bugreports.qt.io", + qUtf16Printable(QString::fromCFString(CFCopyTypeIDDescription(typeId)))); } return QVariant(result); } diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp index ca1a866842..9c201e770b 100644 --- a/src/corelib/tools/qregularexpression.cpp +++ b/src/corelib/tools/qregularexpression.cpp @@ -1048,8 +1048,8 @@ void QRegularExpressionPrivate::getPatternInfo() unsigned int hasJOptionChanged; pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_JCHANGED, &hasJOptionChanged); if (Q_UNLIKELY(hasJOptionChanged)) { - qWarning("QRegularExpressionPrivate::getPatternInfo(): the pattern '%s'\n is using the (?J) option; duplicate capturing group names are not supported by Qt", - qPrintable(pattern)); + qWarning("QRegularExpressionPrivate::getPatternInfo(): the pattern '%ls'\n is using the (?J) option; duplicate capturing group names are not supported by Qt", + qUtf16Printable(pattern)); } } -- cgit v1.2.3 From 54a93af966d3aca8a970e0291d237d95cc3aec64 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 29 May 2019 18:15:45 +0200 Subject: QtCore: use qUtf16Printable and %ls, qErrnoWarning() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... instead of qPrintable(), %s, and explicit qt_error_string(). Saves 2KiB in text size on optimized Linux AMD64 GCC 9.1 builds. Change-Id: I98b6717da1ed1b678f01167d704a96f10da47966 Reviewed-by: Mårten Nordheim Reviewed-by: Thiago Macieira --- src/corelib/kernel/qeventdispatcher_win.cpp | 6 +++--- src/corelib/kernel/qobject.cpp | 4 ++-- src/corelib/mimetypes/qmimeprovider.cpp | 2 +- src/corelib/plugin/qlibrary.cpp | 20 ++++++++++---------- src/corelib/statemachine/qstatemachine.cpp | 4 ++-- src/corelib/thread/qmutex_unix.cpp | 2 +- src/corelib/thread/qthread_unix.cpp | 8 +++----- src/corelib/thread/qwaitcondition_unix.cpp | 2 +- 8 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index acc66ed107..9ec649394d 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -342,7 +342,7 @@ QWindowsMessageWindowClassContext::QWindowsMessageWindowClassContext() wc.lpszClassName = className; atom = RegisterClass(&wc); if (!atom) { - qErrnoWarning("%s RegisterClass() failed", qPrintable(qClassName)); + qErrnoWarning("%ls RegisterClass() failed", qUtf16Printable(qClassName)); delete [] className; className = 0; } @@ -504,8 +504,8 @@ void QEventDispatcherWin32::installMessageHook() d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId()); if (Q_UNLIKELY(!d->getMessageHook)) { int errorCode = GetLastError(); - qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s", - errorCode, qPrintable(qt_error_string(errorCode))); + qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %ls", + errorCode, qUtf16Printable(qt_error_string(errorCode))); } } diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 9c3e67c781..965857d408 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -1759,11 +1759,11 @@ void QObject::killTimer(int id) int at = d->extraData ? d->extraData->runningTimers.indexOf(id) : -1; if (at == -1) { // timer isn't owned by this object - qWarning("QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %s), timer has not been killed", + qWarning("QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %ls), timer has not been killed", id, this, metaObject()->className(), - qPrintable(objectName())); + qUtf16Printable(objectName())); return; } diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp index 7e2696b719..a3a6b9615c 100644 --- a/src/corelib/mimetypes/qmimeprovider.cpp +++ b/src/corelib/mimetypes/qmimeprovider.cpp @@ -673,7 +673,7 @@ void QMimeXMLProvider::load(const QString &fileName) { QString errorMessage; if (!load(fileName, &errorMessage)) - qWarning("QMimeDatabase: Error loading %s\n%s", qPrintable(fileName), qPrintable(errorMessage)); + qWarning("QMimeDatabase: Error loading %ls\n%ls", qUtf16Printable(fileName), qUtf16Printable(errorMessage)); } bool QMimeXMLProvider::load(const QString &fileName, QString *errorMessage) diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 3aadd1a73b..533a2790b9 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -241,8 +241,8 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib) if (lib) lib->errorString = file.errorString(); if (qt_debug_component()) { - qWarning("%s: %s", QFile::encodeName(library).constData(), - qPrintable(QSystemError::stdString())); + qWarning("%s: %ls", QFile::encodeName(library).constData(), + qUtf16Printable(QSystemError::stdString())); } return false; } @@ -275,7 +275,7 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib) int r = QElfParser().parse(filedata, fdlen, library, lib, &pos, &fdlen); if (r == QElfParser::Corrupt || r == QElfParser::NotElf) { if (lib && qt_debug_component()) { - qWarning("QElfParser: %s",qPrintable(lib->errorString)); + qWarning("QElfParser: %ls", qUtf16Printable(lib->errorString)); } return false; } else if (r == QElfParser::QtMetaDataSection) { @@ -292,7 +292,7 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib) int r = QMachOParser::parse(filedata, fdlen, library, &errorString, &pos, &fdlen); if (r == QMachOParser::NotSuitable) { if (qt_debug_component()) - qWarning("QMachOParser: %s", qPrintable(errorString)); + qWarning("QMachOParser: %ls", qUtf16Printable(errorString)); if (lib) lib->errorString = errorString; return false; @@ -319,8 +319,8 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib) QString errMsg; QJsonDocument doc = qJsonFromRawLibraryMetaData(data, fdlen, &errMsg); if (doc.isNull()) { - qWarning("Found invalid metadata in lib %s: %s", - qPrintable(library), qPrintable(errMsg)); + qWarning("Found invalid metadata in lib %ls: %ls", + qUtf16Printable(library), qUtf16Printable(errMsg)); } else { lib->metaData = doc.object(); if (qt_debug_component()) @@ -356,11 +356,11 @@ static void installCoverageTool(QLibraryPrivate *libPrivate) if (qt_debug_component()) { if (ret >= 0) { - qDebug("coverage data for %s registered", - qPrintable(libPrivate->fileName)); + qDebug("coverage data for %ls registered", + qUtf16Printable(libPrivate->fileName)); } else { - qWarning("could not register %s: error %d; coverage data may be incomplete", - qPrintable(libPrivate->fileName), + qWarning("could not register %ls: error %d; coverage data may be incomplete", + qUtf16Printable(libPrivate->fileName), ret); } } diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index e6dfacc0f5..3a86d971e2 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -1526,8 +1526,8 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta addAncestorStatesToEnter(currentErrorState, rootState(), pendingErrorStates, pendingErrorStatesForDefaultEntry); pendingErrorStates -= configuration; } else { - qWarning("Unrecoverable error detected in running state machine: %s", - qPrintable(errorString)); + qWarning("Unrecoverable error detected in running state machine: %ls", + qUtf16Printable(errorString)); q->stop(); } } diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index a92ac4f943..df2f606a23 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE static void report_error(int code, const char *where, const char *what) { if (code != 0) - qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code))); + qErrnoWarning(code, "%s: %s failure", where, what); } #ifdef QT_UNIX_SEMAPHORE diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 8328e514a8..3d4c906dc2 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -714,8 +714,7 @@ void QThread::start(Priority priority) #endif // _POSIX_THREAD_ATTR_STACKSIZE if (code) { - qWarning("QThread::start: Thread stack size error: %s", - qPrintable(qt_error_string(code))); + qErrnoWarning(code, "QThread::start: Thread stack size error"); // we failed to set the stacksize, and as the documentation states, // the thread will fail to run... @@ -740,7 +739,7 @@ void QThread::start(Priority priority) pthread_attr_destroy(&attr); if (code) { - qWarning("QThread::start: Thread creation error: %s", qPrintable(qt_error_string(code))); + qErrnoWarning(code, "QThread::start: Thread creation error"); d->running = false; d->finished = false; @@ -759,8 +758,7 @@ void QThread::terminate() int code = pthread_cancel(from_HANDLE(d->data->threadId.load())); if (code) { - qWarning("QThread::start: Thread termination error: %s", - qPrintable(qt_error_string((code)))); + qErrnoWarning(code, "QThread::start: Thread termination error"); } #endif } diff --git a/src/corelib/thread/qwaitcondition_unix.cpp b/src/corelib/thread/qwaitcondition_unix.cpp index 0ba90763cf..dd7475cec5 100644 --- a/src/corelib/thread/qwaitcondition_unix.cpp +++ b/src/corelib/thread/qwaitcondition_unix.cpp @@ -72,7 +72,7 @@ __attribute__((weakref("__pthread_cond_timedwait_relative"))); static void report_error(int code, const char *where, const char *what) { if (code != 0) - qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code))); + qErrnoWarning(code, "%s: %s failure", where, what); } void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where) -- cgit v1.2.3 From e4c0fca194f8549f3b0fa8a45cf544e01ae6d1b2 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 14 May 2019 20:42:01 +0200 Subject: RelationalTableModel example: use std::unique_ptr instead of QScopedPointer There's talk that QScopedPointer may be deprecated. Don't use it in examples anymore. Change-Id: I3c4647a569b72cd3a628c9b92ef34c87fd588342 Reviewed-by: Giuseppe D'Angelo --- examples/sql/relationaltablemodel/relationaltablemodel.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/sql/relationaltablemodel/relationaltablemodel.cpp b/examples/sql/relationaltablemodel/relationaltablemodel.cpp index c3c7d48d70..df4eae6e6e 100644 --- a/examples/sql/relationaltablemodel/relationaltablemodel.cpp +++ b/examples/sql/relationaltablemodel/relationaltablemodel.cpp @@ -53,6 +53,8 @@ #include "../connection.h" +#include + void initializeModel(QSqlRelationalTableModel *model) { //! [0] @@ -76,12 +78,12 @@ void initializeModel(QSqlRelationalTableModel *model) model->select(); } -QTableView *createView(const QString &title, QSqlTableModel *model) +std::unique_ptr createView(const QString &title, QSqlTableModel *model) { //! [4] - QTableView *view = new QTableView; + std::unique_ptr view{new QTableView}; view->setModel(model); - view->setItemDelegate(new QSqlRelationalDelegate(view)); + view->setItemDelegate(new QSqlRelationalDelegate(view.get())); //! [4] view->setWindowTitle(title); return view; @@ -118,7 +120,7 @@ int main(int argc, char *argv[]) initializeModel(&model); - QScopedPointer view(createView(QObject::tr("Relational Table Model"), &model)); + std::unique_ptr view = createView(QObject::tr("Relational Table Model"), &model); view->show(); return app.exec(); -- cgit v1.2.3 From af7e0e735777d7f7d1606049e5261106a092665a Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 28 May 2019 22:11:24 +0200 Subject: De-duplicate code for calling extra compiler depend_command Flesh out copy-and-pasted code into a function and adjust the coding style on the go. Change-Id: I9b8a87d6dd5c33cc1ed9f613fe85daca52309369 Reviewed-by: Christian Kandeler --- qmake/generators/makefile.cpp | 129 +++++++++++++++++------------------------- qmake/generators/makefile.h | 3 + 2 files changed, 56 insertions(+), 76 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 95452e507c..f3ca192ab2 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -1862,6 +1862,55 @@ QString MakefileGenerator::resolveDependency(const QDir &outDir, const QString & return {}; } +void MakefileGenerator::callExtraCompilerDependCommand(const ProString &extraCompiler, + const QString &dep_cd_cmd, + const QString &tmp_dep_cmd, + const QString &inpf, + const QString &tmp_out, + bool dep_lines, + QStringList *deps) +{ + char buff[256]; + QString dep_cmd = replaceExtraCompilerVariables(tmp_dep_cmd, inpf, tmp_out, LocalShell); + dep_cmd = dep_cd_cmd + fixEnvVariables(dep_cmd); + if (FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), QT_POPEN_READ)) { + QByteArray depData; + while (int read_in = feof(proc) ? 0 : (int)fread(buff, 1, 255, proc)) + depData.append(buff, read_in); + QT_PCLOSE(proc); + const QString indeps = QString::fromLocal8Bit(depData); + if (indeps.isEmpty()) + return; + QDir outDir(Option::output_dir); + QStringList dep_cmd_deps = splitDeps(indeps, dep_lines); + for (int i = 0; i < dep_cmd_deps.count(); ++i) { + QString &file = dep_cmd_deps[i]; + const QString absFile = outDir.absoluteFilePath(file); + if (absFile == file) { + // already absolute; don't do any checks. + } else if (exists(absFile)) { + file = absFile; + } else { + const QString localFile = resolveDependency(outDir, file); + if (localFile.isEmpty()) { + if (exists(file)) { + warn_msg(WarnDeprecated, ".depend_command for extra compiler %s" + " prints paths relative to source directory", + extraCompiler.toLatin1().constData()); + } else { + file = absFile; // fallback for generated resources + } + } else { + file = localFile; + } + } + if (!file.isEmpty()) + file = fileFixify(file); + } + deps->append(dep_cmd_deps); + } +} + void MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) { @@ -1991,44 +2040,8 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) deps += findDependencies(inpf); inputs += Option::fixPathToTargetOS(inpf, false); if(!tmp_dep_cmd.isEmpty() && doDepends()) { - char buff[256]; - QString dep_cmd = replaceExtraCompilerVariables(tmp_dep_cmd, inpf, tmp_out, LocalShell); - dep_cmd = dep_cd_cmd + fixEnvVariables(dep_cmd); - if (FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), QT_POPEN_READ)) { - QByteArray depData; - while (int read_in = feof(proc) ? 0 : (int)fread(buff, 1, 255, proc)) - depData.append(buff, read_in); - QT_PCLOSE(proc); - const QString indeps = QString::fromLocal8Bit(depData); - if(!indeps.isEmpty()) { - QDir outDir(Option::output_dir); - QStringList dep_cmd_deps = splitDeps(indeps, dep_lines); - for(int i = 0; i < dep_cmd_deps.count(); ++i) { - QString &file = dep_cmd_deps[i]; - QString absFile = outDir.absoluteFilePath(file); - if (absFile == file) { - // already absolute; don't do any checks. - } else if (exists(absFile)) { - file = absFile; - } else { - QString localFile = resolveDependency(outDir, file); - if (localFile.isEmpty()) { - if (exists(file)) - warn_msg(WarnDeprecated, ".depend_command for extra compiler %s" - " prints paths relative to source directory", - (*it).toLatin1().constData()); - else - file = absFile; // fallback for generated resources - } else { - file = localFile; - } - } - if(!file.isEmpty()) - file = fileFixify(file); - } - deps += dep_cmd_deps; - } - } + callExtraCompilerDependCommand(*it, dep_cd_cmd, tmp_dep_cmd, inpf, + tmp_out, dep_lines, &deps); } } for(int i = 0; i < inputs.size(); ) { @@ -2076,44 +2089,8 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) for (ProStringList::ConstIterator it3 = vars.constBegin(); it3 != vars.constEnd(); ++it3) cmd.replace("$(" + (*it3) + ")", "$(QMAKE_COMP_" + (*it3)+")"); if(!tmp_dep_cmd.isEmpty() && doDepends()) { - char buff[256]; - QString dep_cmd = replaceExtraCompilerVariables(tmp_dep_cmd, inpf, out, LocalShell); - dep_cmd = dep_cd_cmd + fixEnvVariables(dep_cmd); - if (FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), QT_POPEN_READ)) { - QByteArray depData; - while (int read_in = feof(proc) ? 0 : (int)fread(buff, 1, 255, proc)) - depData.append(buff, read_in); - QT_PCLOSE(proc); - const QString indeps = QString::fromLocal8Bit(depData); - if(!indeps.isEmpty()) { - QDir outDir(Option::output_dir); - QStringList dep_cmd_deps = splitDeps(indeps, dep_lines); - for(int i = 0; i < dep_cmd_deps.count(); ++i) { - QString &file = dep_cmd_deps[i]; - QString absFile = outDir.absoluteFilePath(file); - if (absFile == file) { - // already absolute; don't do any checks. - } else if (exists(absFile)) { - file = absFile; - } else { - QString localFile = resolveDependency(outDir, file); - if (localFile.isEmpty()) { - if (exists(file)) - warn_msg(WarnDeprecated, ".depend_command for extra compiler %s" - " prints paths relative to source directory", - (*it).toLatin1().constData()); - else - file = absFile; // fallback for generated resources - } else { - file = localFile; - } - } - if(!file.isEmpty()) - file = fileFixify(file); - } - deps += dep_cmd_deps; - } - } + callExtraCompilerDependCommand(*it, dep_cd_cmd, tmp_dep_cmd, inpf, + tmp_out, dep_lines, &deps); //use the depend system to find includes of these included files QStringList inc_deps; for(int i = 0; i < deps.size(); ++i) { diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h index ecda6eb257..c7b2bee0b4 100644 --- a/qmake/generators/makefile.h +++ b/qmake/generators/makefile.h @@ -84,6 +84,9 @@ protected: void writeExtraVariables(QTextStream &t); void writeExtraTargets(QTextStream &t); QString resolveDependency(const QDir &outDir, const QString &file); + void callExtraCompilerDependCommand(const ProString &extraCompiler, const QString &dep_cd_cmd, + const QString &tmp_dep_cmd, const QString &inpf, + const QString &tmp_out, bool dep_lines, QStringList *deps); void writeExtraCompilerTargets(QTextStream &t); void writeExtraCompilerVariables(QTextStream &t); bool writeDummyMakefile(QTextStream &t); -- cgit v1.2.3 From f239cd5797e0fac1254adaccea61fe27408cea58 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 29 May 2019 14:00:05 +0200 Subject: Remove unneeded qstring_compat.cpp from the qmake build Change-Id: Ie25aca49e8ff6a7aeb50dd77c36e5e1391d9c00e Reviewed-by: Edward Welbourne Reviewed-by: Thiago Macieira --- qmake/Makefile.unix | 6 +----- qmake/Makefile.win32 | 6 +----- qmake/qmake.pro | 1 - 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix index 166ec33c1b..9898346dbe 100644 --- a/qmake/Makefile.unix +++ b/qmake/Makefile.unix @@ -30,7 +30,7 @@ QOBJS = \ qarraydata.o qbitarray.o qbytearray.o qbytearraymatcher.o \ qcryptographichash.o qdatetime.o qhash.o qlist.o \ qlocale.o qlocale_tools.o qmap.o qregexp.o qringbuffer.o \ - qstringbuilder.o qstring_compat.o qstring.o qstringlist.o qversionnumber.o \ + qstringbuilder.o qstring.o qstringlist.o qversionnumber.o \ qvsnprintf.o qxmlstream.o qxmlutils.o \ $(QTOBJS) $(QTOBJS2) # QTOBJS and QTOBJS2 are populated by Makefile.unix.* as for QTSRC (see below). @@ -119,7 +119,6 @@ DEPEND_SRC = \ $(SOURCE_PATH)/src/corelib/tools/qregexp.cpp \ $(SOURCE_PATH)/src/corelib/tools/qringbuffer.cpp \ $(SOURCE_PATH)/src/corelib/tools/qstringbuilder.cpp \ - $(SOURCE_PATH)/src/corelib/tools/qstring_compat.cpp \ $(SOURCE_PATH)/src/corelib/tools/qstring.cpp \ $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp \ $(SOURCE_PATH)/src/corelib/tools/qversionnumber.cpp \ @@ -342,9 +341,6 @@ qutfcodec.o: $(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp qstring.o: $(SOURCE_PATH)/src/corelib/tools/qstring.cpp $(CXX) -c -o $@ $(CXXFLAGS) $< -qstring_compat.o: $(SOURCE_PATH)/src/corelib/tools/qstring_compat.cpp - $(CXX) -c -o $@ $(CXXFLAGS) $< - qstringbuilder.o: $(SOURCE_PATH)/src/corelib/tools/qstringbuilder.cpp $(CXX) -c -o $@ $(CXXFLAGS) $< diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32 index 1777741df4..5fa49d2f7f 100644 --- a/qmake/Makefile.win32 +++ b/qmake/Makefile.win32 @@ -99,7 +99,6 @@ QTOBJS= \ qregexp.obj \ qutfcodec.obj \ qstring.obj \ - qstring_compat.obj \ qstringlist.obj \ qstringbuilder.obj \ qsystemerror.obj \ @@ -200,10 +199,7 @@ qmake_pch.obj: {$(SOURCE_PATH)\src\corelib\tools}.cpp{}.obj:: $(CXX) $(CXXFLAGS) $< -# Make sure qstring_compat.obj and qlibraryinfo.obj aren't compiled with PCH enabled -qstring_compat.obj: $(SOURCE_PATH)\src\corelib\tools\qstring_compat.cpp - $(CXX) -c $(CXXFLAGS_BARE) $(SOURCE_PATH)\src\corelib\tools\qstring_compat.cpp - +# Make sure qlibraryinfo.obj isn't compiled with PCH enabled qlibraryinfo.obj: $(SOURCE_PATH)\src\corelib\global\qlibraryinfo.cpp $(CXX) $(CXXFLAGS_BARE) -DQT_BUILD_QMAKE_BOOTSTRAP $(SOURCE_PATH)\src\corelib\global\qlibraryinfo.cpp diff --git a/qmake/qmake.pro b/qmake/qmake.pro index 276c1237a9..4681fbf764 100644 --- a/qmake/qmake.pro +++ b/qmake/qmake.pro @@ -147,7 +147,6 @@ SOURCES += \ qregexp.cpp \ qsettings.cpp \ qstring.cpp \ - qstring_compat.cpp \ qstringlist.cpp \ qsystemerror.cpp \ qtemporaryfile.cpp \ -- cgit v1.2.3 From 6a7cea64d20759ee4ff1e0c2f682868e2907661f Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Mon, 25 Mar 2019 18:05:14 +0200 Subject: QEventDispatcherWin32: rework sending of posted events Since its initial implementation, QEventDispatcherWin32 manages a delivery of the posted events from the window procedure through WM_QT_SENDPOSTEDEVENTS message. That makes the implementation quite difficult and unclear. As a result, posted events get stalled, in case of using nested event loops or other recursion. The proposed solution is to send posted events at the beginning of processEvents() only once per iteration of the event loop. However, in case of using a foreign event loop (e.g. by opening a native modal dialog), we should leave the emission in the window procedure, as we don't control its execution. Task-number: QTBUG-74564 Change-Id: Ib7ce85b65405af6124823dda1451d1370aed9b1a Reviewed-by: Volker Hilsheimer --- src/corelib/kernel/qeventdispatcher_win.cpp | 124 +++++++++++++--------------- src/corelib/kernel/qeventdispatcher_win_p.h | 2 - 2 files changed, 56 insertions(+), 70 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 9ec649394d..e0641a0282 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -82,8 +82,13 @@ extern uint qGlobalPostedEventsCount(); enum { WM_QT_SOCKETNOTIFIER = WM_USER, WM_QT_SENDPOSTEDEVENTS = WM_USER + 1, - WM_QT_ACTIVATENOTIFIERS = WM_USER + 2, - SendPostedEventsWindowsTimerId = ~1u + WM_QT_ACTIVATENOTIFIERS = WM_USER + 2 +}; + +// WM_QT_SENDPOSTEDEVENTS message parameter +enum { + WMWP_QT_TOFOREIGNLOOP = 0, + WMWP_QT_FROMWAKEUP }; class QEventDispatcherWin32Private; @@ -96,8 +101,8 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA QEventDispatcherWin32Private::QEventDispatcherWin32Private() : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0), - getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0), - wakeUps(0), activateNotifiersPosted(false), winEventNotifierActivatedEvent(NULL) + getMessageHook(0), wakeUps(0), activateNotifiersPosted(false), + winEventNotifierActivatedEvent(NULL) { } @@ -234,22 +239,20 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA return 0; } case WM_TIMER: - if (d->sendPostedEventsWindowsTimerId == 0 - || wp != uint(d->sendPostedEventsWindowsTimerId)) { - Q_ASSERT(d != 0); - d->sendTimerEvent(wp); - return 0; - } - // we also use a Windows timer to send posted events when the message queue is full - Q_FALLTHROUGH(); - case WM_QT_SENDPOSTEDEVENTS: { - const int localSerialNumber = d->serialNumber.load(); - if (localSerialNumber != d->lastSerialNumber) { - d->lastSerialNumber = localSerialNumber; - q->sendPostedEvents(); - } + Q_ASSERT(d != 0); + + d->sendTimerEvent(wp); + return 0; + case WM_QT_SENDPOSTEDEVENTS: + Q_ASSERT(d != 0); + + // Allow posting WM_QT_SENDPOSTEDEVENTS message. + d->wakeUps.store(0); + + // We send posted events manually, if the window procedure was invoked + // by the foreign event loop (e.g. from the native modal dialog). + q->sendPostedEvents(); return 0; - } } // switch (message) return DefWindowProc(hwnd, message, wp, lp); @@ -272,39 +275,6 @@ LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp) QEventDispatcherWin32 *q = qobject_cast(QAbstractEventDispatcher::instance()); Q_ASSERT(q != 0); - if (wp == PM_REMOVE) { - if (q) { - MSG *msg = (MSG *) lp; - QEventDispatcherWin32Private *d = q->d_func(); - const int localSerialNumber = d->serialNumber.load(); - static const UINT mask = inputTimerMask(); - if (HIWORD(GetQueueStatus(mask)) == 0) { - // no more input or timer events in the message queue, we can allow posted events to be sent normally now - if (d->sendPostedEventsWindowsTimerId != 0) { - // stop the timer to send posted events, since we now allow the WM_QT_SENDPOSTEDEVENTS message - KillTimer(d->internalHwnd, d->sendPostedEventsWindowsTimerId); - d->sendPostedEventsWindowsTimerId = 0; - } - (void) d->wakeUps.fetchAndStoreRelease(0); - if (localSerialNumber != d->lastSerialNumber - // if this message IS the one that triggers sendPostedEvents(), no need to post it again - && (msg->hwnd != d->internalHwnd - || msg->message != WM_QT_SENDPOSTEDEVENTS)) { - PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); - } - } else if (d->sendPostedEventsWindowsTimerId == 0 - && localSerialNumber != d->lastSerialNumber) { - // start a special timer to continue delivering posted events while - // there are still input and timer messages in the message queue - d->sendPostedEventsWindowsTimerId = SetTimer(d->internalHwnd, - SendPostedEventsWindowsTimerId, - 0, // we specify zero, but Windows uses USER_TIMER_MINIMUM - NULL); - // we don't check the return value of SetTimer()... if creating the timer failed, there's little - // we can do. we just have to accept that posted events will be starved - } - } - } return q->d_func()->getMessageHook ? CallNextHookEx(0, code, wp, lp) : 0; } @@ -559,9 +529,12 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) d->interrupt.store(false); emit awake(); + // To prevent livelocks, send posted events once per iteration. + // QCoreApplication::sendPostedEvents() takes care about recursions. + sendPostedEvents(); + bool canWait; bool retVal = false; - bool seenWM_QT_SENDPOSTEDEVENTS = false; bool needWM_QT_SENDPOSTEDEVENTS = false; do { DWORD waitRet = 0; @@ -615,14 +588,15 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) (void) qt_GetMessageHook(0, PM_REMOVE, reinterpret_cast(&msg)); if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) { - if (seenWM_QT_SENDPOSTEDEVENTS) { - // when calling processEvents() "manually", we only want to send posted - // events once - needWM_QT_SENDPOSTEDEVENTS = true; - continue; + // Set result to 'true', if the message was sent by wakeUp(). + if (msg.wParam == WMWP_QT_FROMWAKEUP) { + d->wakeUps.store(0); + retVal = true; } - seenWM_QT_SENDPOSTEDEVENTS = true; - } else if (msg.message == WM_TIMER) { + needWM_QT_SENDPOSTEDEVENTS = true; + continue; + } + if (msg.message == WM_TIMER) { // avoid live-lock by keeping track of the timers we've already sent bool found = false; for (int i = 0; !found && i < processedTimers.count(); ++i) { @@ -639,10 +613,22 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) } if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) { + // Post WM_QT_SENDPOSTEDEVENTS before calling external code, + // as it can start a foreign event loop. + if (needWM_QT_SENDPOSTEDEVENTS) { + needWM_QT_SENDPOSTEDEVENTS = false; + PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, + WMWP_QT_TOFOREIGNLOOP, 0); + } TranslateMessage(&msg); DispatchMessage(&msg); } } else if (waitRet - WAIT_OBJECT_0 < nCount) { + if (needWM_QT_SENDPOSTEDEVENTS) { + needWM_QT_SENDPOSTEDEVENTS = false; + PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, + WMWP_QT_TOFOREIGNLOOP, 0); + } activateEventNotifiers(); } else { // nothing todo so break @@ -660,19 +646,20 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); emit awake(); if (waitRet - WAIT_OBJECT_0 < nCount) { + if (needWM_QT_SENDPOSTEDEVENTS) { + needWM_QT_SENDPOSTEDEVENTS = false; + PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, + WMWP_QT_TOFOREIGNLOOP, 0); + } activateEventNotifiers(); retVal = true; } } } while (canWait); - if (!seenWM_QT_SENDPOSTEDEVENTS && (flags & QEventLoop::EventLoopExec) == 0) { - // when called "manually", always send posted events - sendPostedEvents(); - } - if (needWM_QT_SENDPOSTEDEVENTS) - PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); + PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, + WMWP_QT_TOFOREIGNLOOP, 0); return retVal; } @@ -1016,10 +1003,11 @@ int QEventDispatcherWin32::remainingTime(int timerId) void QEventDispatcherWin32::wakeUp() { Q_D(QEventDispatcherWin32); - d->serialNumber.ref(); if (d->internalHwnd && d->wakeUps.testAndSetAcquire(0, 1)) { // post a WM_QT_SENDPOSTEDEVENTS to this thread if there isn't one already pending - PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); + if (!PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, + WMWP_QT_FROMWAKEUP, 0)) + qErrnoWarning("QEventDispatcherWin32::wakeUp: Failed to post a message"); } } diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index dbad2a5450..f672530ff8 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -172,8 +172,6 @@ public: HHOOK getMessageHook; // for controlling when to send posted events - QAtomicInt serialNumber; - int lastSerialNumber, sendPostedEventsWindowsTimerId; QAtomicInt wakeUps; // timers -- cgit v1.2.3 From a5b373e0db45a28c133bf413e00f15271aa20200 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Sat, 1 Jun 2019 17:11:42 +0200 Subject: tst_qtextbrowser: add markdown test data to TESTDATA It's necessary to make the test pass on certain platforms. Change-Id: I717d492df437c0ffb75b21d9ef23ce602160fad1 Reviewed-by: Shawn Rutledge --- tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro b/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro index 9680ffd871..05c156bf59 100644 --- a/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro +++ b/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro @@ -4,6 +4,6 @@ SOURCES += tst_qtextbrowser.cpp QT += widgets testlib -TESTDATA += *.html subdir/* +TESTDATA += *.html *.md subdir/* builtin_testdata: DEFINES += BUILTIN_TESTDATA -- cgit v1.2.3 From 0eb26c144346dcb12008e5b3e9441073f09668a8 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Sun, 19 May 2019 13:06:05 +0200 Subject: QTextBrowser: detect and load markdown rather than assuming HTML So we add the QTextDocument::ResourceType::MarkdownResource enum value to indicate the type. QMimeDatabase is generally unable to detect markdown by "magic", so we need to use the common file extensions to detect it (the same extensions as declared in the mime database XML). Change-Id: Ib71f03abd535c17e5a8c99bd92d0a6062e972837 Reviewed-by: Simon Hausmann --- src/gui/text/qtextdocument.cpp | 1 + src/gui/text/qtextdocument.h | 1 + src/widgets/widgets/qtextbrowser.cpp | 20 +++++++++++++++++++- tests/auto/widgets/widgets/qtextbrowser/markdown.md | 2 ++ .../widgets/qtextbrowser/tst_qtextbrowser.cpp | 16 ++++++++++++++++ 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/auto/widgets/widgets/qtextbrowser/markdown.md diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 3266819bf3..c800cea3f6 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -2076,6 +2076,7 @@ void QTextDocument::print(QPagedPaintDevice *printer) const The icon needs to be converted to one of the supported types first, for example using QIcon::pixmap. \value StyleSheetResource The resource contains CSS. + \value MarkdownResource The resource contains Markdown. \value UserResource The first available value for user defined resource types. diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index 31c06976a5..edb6bd9310 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -228,6 +228,7 @@ public: HtmlResource = 1, ImageResource = 2, StyleSheetResource = 3, + MarkdownResource = 4, UserResource = 100 }; diff --git a/src/widgets/widgets/qtextbrowser.cpp b/src/widgets/widgets/qtextbrowser.cpp index 91c5f62246..8e06efc75e 100644 --- a/src/widgets/widgets/qtextbrowser.cpp +++ b/src/widgets/widgets/qtextbrowser.cpp @@ -57,9 +57,12 @@ #endif #include #include +#include QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcBrowser, "qt.text.browser") + class QTextBrowserPrivate : public QTextEditPrivate { Q_DECLARE_PUBLIC(QTextBrowser) @@ -288,10 +291,18 @@ void QTextBrowserPrivate::setSource(const QUrl &url) currentUrlWithoutFragment.setFragment(QString()); QUrl newUrlWithoutFragment = currentURL.resolved(url); newUrlWithoutFragment.setFragment(QString()); + QTextDocument::ResourceType type = QTextDocument::HtmlResource; + QString fileName = url.fileName(); +#if QT_CONFIG(textmarkdownreader) + if (fileName.endsWith(QLatin1String(".md")) || + fileName.endsWith(QLatin1String(".mkd")) || + fileName.endsWith(QLatin1String(".markdown"))) + type = QTextDocument::MarkdownResource; +#endif if (url.isValid() && (newUrlWithoutFragment != currentUrlWithoutFragment || forceLoadOnSourceChange)) { - QVariant data = q->loadResource(QTextDocument::HtmlResource, resolveUrl(url)); + QVariant data = q->loadResource(type, resolveUrl(url)); if (data.type() == QVariant::String) { txt = data.toString(); } else if (data.type() == QVariant::ByteArray) { @@ -334,6 +345,12 @@ void QTextBrowserPrivate::setSource(const QUrl &url) if (!baseUrl.path().isEmpty()) q->document()->setBaseUrl(baseUrl); q->document()->setMetaInformation(QTextDocument::DocumentUrl, currentURL.toString()); + qCDebug(lcBrowser) << "loading" << currentURL << "base" << q->document()->baseUrl() << "type" << type << txt.size() << "chars"; +#if QT_CONFIG(textmarkdownreader) + if (type == QTextDocument::MarkdownResource) + q->QTextEdit::setMarkdown(txt); + else +#endif #ifndef QT_NO_TEXTHTMLPARSER q->QTextEdit::setHtml(txt); #else @@ -1092,6 +1109,7 @@ void QTextBrowser::paintEvent(QPaintEvent *e) \row \li QTextDocument::HtmlResource \li QString or QByteArray \row \li QTextDocument::ImageResource \li QImage, QPixmap or QByteArray \row \li QTextDocument::StyleSheetResource \li QString or QByteArray + \row \li QTextDocument::MarkdownResource \li QString or QByteArray \endtable */ QVariant QTextBrowser::loadResource(int /*type*/, const QUrl &name) diff --git a/tests/auto/widgets/widgets/qtextbrowser/markdown.md b/tests/auto/widgets/widgets/qtextbrowser/markdown.md new file mode 100644 index 0000000000..be56aef234 --- /dev/null +++ b/tests/auto/widgets/widgets/qtextbrowser/markdown.md @@ -0,0 +1,2 @@ +### this is a heading +this is a paragraph diff --git a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp index 1f95032165..22cd3b46c6 100644 --- a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp +++ b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp @@ -92,6 +92,7 @@ private slots: void focusIndicator(); void focusHistory(); void urlEncoding(); + void markdown(); private: TestBrowser *browser; @@ -678,5 +679,20 @@ void tst_QTextBrowser::urlEncoding() delete browser; } +void tst_QTextBrowser::markdown() +{ + browser->setSource(QUrl::fromLocalFile(QFINDTESTDATA("markdown.md"))); + QTextFrame::iterator iterator = browser->document()->rootFrame()->begin(); + int maxHeadingLevel = -1; + while (!iterator.atEnd()) + maxHeadingLevel = qMax(iterator++.currentBlock().blockFormat().intProperty(QTextFormat::HeadingLevel), maxHeadingLevel); +#if QT_CONFIG(textmarkdownreader) + QCOMPARE(maxHeadingLevel, 3); +#else + // If Qt doesn't support markdown, this document will be misidentified as HTML, so it won't have any H3's. + QCOMPARE(maxHeadingLevel, 0); +#endif +} + QTEST_MAIN(tst_QTextBrowser) #include "tst_qtextbrowser.moc" -- cgit v1.2.3 From ca0c9f82cbf7c8c37acdcbdfdc3fa0c5fc138059 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 24 May 2019 21:41:17 +0200 Subject: QGraphicsWidget: overload two margins-setters with actual QMarginsF overloads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace manual memory management with unique_ptr and manual re-implementations of QMarginsF with The Real Thing™. The only noticeable difference should be that the checks for 0 now use qFuzzyCompare() (by way of QMarginsF::isNull() and its operator==). [ChangeLog][QtWidgets][QGraphicsWidget] Added QMarginsF overloads of setContentsMargins() and setWindowFrameMargins(). Change-Id: I6b3bb87015fa52fdde245b7528cca4b8f9ce41e1 Reviewed-by: Mårten Nordheim Reviewed-by: Richard Moe Gustavsen --- src/widgets/graphicsview/qgraphicswidget.cpp | 92 ++++++++++++++------------ src/widgets/graphicsview/qgraphicswidget.h | 2 + src/widgets/graphicsview/qgraphicswidget_p.cpp | 26 +++----- src/widgets/graphicsview/qgraphicswidget_p.h | 7 +- 4 files changed, 67 insertions(+), 60 deletions(-) diff --git a/src/widgets/graphicsview/qgraphicswidget.cpp b/src/widgets/graphicsview/qgraphicswidget.cpp index ad3be5766d..cd647a5db1 100644 --- a/src/widgets/graphicsview/qgraphicswidget.cpp +++ b/src/widgets/graphicsview/qgraphicswidget.cpp @@ -473,8 +473,9 @@ relayoutChildrenAndReturn: */ /*! - Sets the widget's contents margins to \a left, \a top, \a right and \a - bottom. + \since 5.14 + + Sets the widget's contents margins to \a margins. Contents margins are used by the assigned layout to define the placement of subwidgets and layouts. Margins are particularly useful for widgets @@ -488,23 +489,17 @@ relayoutChildrenAndReturn: \sa getContentsMargins(), setGeometry() */ -void QGraphicsWidget::setContentsMargins(qreal left, qreal top, qreal right, qreal bottom) +void QGraphicsWidget::setContentsMargins(QMarginsF margins) { Q_D(QGraphicsWidget); - if (!d->margins && left == 0 && top == 0 && right == 0 && bottom == 0) + if (!d->margins && margins.isNull()) return; d->ensureMargins(); - if (left == d->margins[d->Left] - && top == d->margins[d->Top] - && right == d->margins[d->Right] - && bottom == d->margins[d->Bottom]) + if (*d->margins == margins) return; - d->margins[d->Left] = left; - d->margins[d->Top] = top; - d->margins[d->Right] = right; - d->margins[d->Bottom] = bottom; + *d->margins = margins; if (QGraphicsLayout *l = d->layout) l->invalidate(); @@ -515,6 +510,17 @@ void QGraphicsWidget::setContentsMargins(qreal left, qreal top, qreal right, qre QApplication::sendEvent(this, &e); } +/*! + \overload + + Sets the widget's contents margins to \a left, \a top, \a right and \a + bottom. +*/ +void QGraphicsWidget::setContentsMargins(qreal left, qreal top, qreal right, qreal bottom) +{ + setContentsMargins({left, top, right, bottom}); +} + /*! Gets the widget's contents margins. The margins are stored in \a left, \a top, \a right and \a bottom, as pointers to qreals. Each argument can @@ -528,18 +534,19 @@ void QGraphicsWidget::getContentsMargins(qreal *left, qreal *top, qreal *right, if (left || top || right || bottom) d->ensureMargins(); if (left) - *left = d->margins[d->Left]; + *left = d->margins->left(); if (top) - *top = d->margins[d->Top]; + *top = d->margins->top(); if (right) - *right = d->margins[d->Right]; + *right = d->margins->right(); if (bottom) - *bottom = d->margins[d->Bottom]; + *bottom = d->margins->bottom(); } /*! - Sets the widget's window frame margins to \a left, \a top, \a right and - \a bottom. The default frame margins are provided by the style, and they + \since 5.14 + Sets the widget's window frame margins to \a margins. + The default frame margins are provided by the style, and they depend on the current window flags. If you would like to draw your own window decoration, you can set your @@ -547,29 +554,32 @@ void QGraphicsWidget::getContentsMargins(qreal *left, qreal *top, qreal *right, \sa unsetWindowFrameMargins(), getWindowFrameMargins(), windowFrameRect() */ -void QGraphicsWidget::setWindowFrameMargins(qreal left, qreal top, qreal right, qreal bottom) +void QGraphicsWidget::setWindowFrameMargins(QMarginsF margins) { Q_D(QGraphicsWidget); - if (!d->windowFrameMargins && left == 0 && top == 0 && right == 0 && bottom == 0) + if (!d->windowFrameMargins && margins.isNull()) return; d->ensureWindowFrameMargins(); - bool unchanged = - d->windowFrameMargins[d->Left] == left - && d->windowFrameMargins[d->Top] == top - && d->windowFrameMargins[d->Right] == right - && d->windowFrameMargins[d->Bottom] == bottom; + const bool unchanged = *d->windowFrameMargins == margins; if (d->setWindowFrameMargins && unchanged) return; if (!unchanged) prepareGeometryChange(); - d->windowFrameMargins[d->Left] = left; - d->windowFrameMargins[d->Top] = top; - d->windowFrameMargins[d->Right] = right; - d->windowFrameMargins[d->Bottom] = bottom; + *d->windowFrameMargins = margins; d->setWindowFrameMargins = true; } +/*! + \overload + Sets the widget's window frame margins to \a left, \a top, \a right and + \a bottom. +*/ +void QGraphicsWidget::setWindowFrameMargins(qreal left, qreal top, qreal right, qreal bottom) +{ + setWindowFrameMargins({left, top, right, bottom}); +} + /*! Gets the widget's window frame margins. The margins are stored in \a left, \a top, \a right and \a bottom as pointers to qreals. Each argument can @@ -583,13 +593,13 @@ void QGraphicsWidget::getWindowFrameMargins(qreal *left, qreal *top, qreal *righ if (left || top || right || bottom) d->ensureWindowFrameMargins(); if (left) - *left = d->windowFrameMargins[d->Left]; + *left = d->windowFrameMargins->left(); if (top) - *top = d->windowFrameMargins[d->Top]; + *top = d->windowFrameMargins->top(); if (right) - *right = d->windowFrameMargins[d->Right]; + *right = d->windowFrameMargins->right(); if (bottom) - *bottom = d->windowFrameMargins[d->Bottom]; + *bottom = d->windowFrameMargins->bottom(); } /*! @@ -624,8 +634,8 @@ QRectF QGraphicsWidget::windowFrameGeometry() const { Q_D(const QGraphicsWidget); return d->windowFrameMargins - ? geometry().adjusted(-d->windowFrameMargins[d->Left], -d->windowFrameMargins[d->Top], - d->windowFrameMargins[d->Right], d->windowFrameMargins[d->Bottom]) + ? geometry().adjusted(-d->windowFrameMargins->left(), -d->windowFrameMargins->top(), + d->windowFrameMargins->right(), d->windowFrameMargins->bottom()) : geometry(); } @@ -638,8 +648,8 @@ QRectF QGraphicsWidget::windowFrameRect() const { Q_D(const QGraphicsWidget); return d->windowFrameMargins - ? rect().adjusted(-d->windowFrameMargins[d->Left], -d->windowFrameMargins[d->Top], - d->windowFrameMargins[d->Right], d->windowFrameMargins[d->Bottom]) + ? rect().adjusted(-d->windowFrameMargins->left(), -d->windowFrameMargins->top(), + d->windowFrameMargins->right(), d->windowFrameMargins->bottom()) : rect(); } @@ -751,8 +761,8 @@ QSizeF QGraphicsWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) c if (d->layout) { QSizeF marginSize(0,0); if (d->margins) { - marginSize = QSizeF(d->margins[d->Left] + d->margins[d->Right], - d->margins[d->Top] + d->margins[d->Bottom]); + marginSize = QSizeF(d->margins->left() + d->margins->right(), + d->margins->top() + d->margins->bottom()); } sh = d->layout->effectiveSizeHint(which, constraint - marginSize); sh += marginSize; @@ -1320,7 +1330,7 @@ Qt::WindowFrameSection QGraphicsWidget::windowFrameSectionAt(const QPointF &pos) const qreal cornerMargin = 20; //### Not sure of this one, it should be the same value for all edges. const qreal windowFrameWidth = d->windowFrameMargins - ? d->windowFrameMargins[d->Left] : 0; + ? d->windowFrameMargins->left() : 0; Qt::WindowFrameSection s = Qt::NoSection; if (x <= left + cornerMargin) { @@ -1347,7 +1357,7 @@ Qt::WindowFrameSection QGraphicsWidget::windowFrameSectionAt(const QPointF &pos) if (s == Qt::NoSection) { QRectF r1 = r; r1.setHeight(d->windowFrameMargins - ? d->windowFrameMargins[d->Top] : 0); + ? d->windowFrameMargins->top() : 0); if (r1.contains(pos)) s = Qt::TitleBarArea; } diff --git a/src/widgets/graphicsview/qgraphicswidget.h b/src/widgets/graphicsview/qgraphicswidget.h index 481fb55db3..8223b921c9 100644 --- a/src/widgets/graphicsview/qgraphicswidget.h +++ b/src/widgets/graphicsview/qgraphicswidget.h @@ -111,9 +111,11 @@ public: inline QRectF rect() const { return QRectF(QPointF(), size()); } void setContentsMargins(qreal left, qreal top, qreal right, qreal bottom); + void setContentsMargins(QMarginsF margins); void getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const override; void setWindowFrameMargins(qreal left, qreal top, qreal right, qreal bottom); + void setWindowFrameMargins(QMarginsF margins); void getWindowFrameMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const; void unsetWindowFrameMargins(); QRectF windowFrameGeometry() const; diff --git a/src/widgets/graphicsview/qgraphicswidget_p.cpp b/src/widgets/graphicsview/qgraphicswidget_p.cpp index 1514fca456..ce027c1319 100644 --- a/src/widgets/graphicsview/qgraphicswidget_p.cpp +++ b/src/widgets/graphicsview/qgraphicswidget_p.cpp @@ -51,6 +51,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE void QGraphicsWidgetPrivate::init(QGraphicsItem *parentItem, Qt::WindowFlags wFlags) @@ -109,8 +111,6 @@ QGraphicsWidgetPrivate::QGraphicsWidgetPrivate() QGraphicsWidgetPrivate::~QGraphicsWidgetPrivate() { // Remove any lazily allocated data - delete[] margins; - delete[] windowFrameMargins; delete windowData; } @@ -122,11 +122,8 @@ QGraphicsWidgetPrivate::~QGraphicsWidgetPrivate() */ void QGraphicsWidgetPrivate::ensureMargins() const { - if (!margins) { - margins = new qreal[4]; - for (int i = 0; i < 4; ++i) - margins[i] = 0; - } + if (!margins) + margins = qt_make_unique(); } /*! @@ -137,11 +134,8 @@ void QGraphicsWidgetPrivate::ensureMargins() const */ void QGraphicsWidgetPrivate::ensureWindowFrameMargins() const { - if (!windowFrameMargins) { - windowFrameMargins = new qreal[4]; - for (int i = 0; i < 4; ++i) - windowFrameMargins[i] = 0; - } + if (!windowFrameMargins) + windowFrameMargins = qt_make_unique(); } /*! @@ -372,8 +366,8 @@ void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEve bar.rect.setHeight(q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &bar)); QPointF pos = event->pos(); if (windowFrameMargins) { - pos.rx() += windowFrameMargins[Left]; - pos.ry() += windowFrameMargins[Top]; + pos.rx() += windowFrameMargins->left(); + pos.ry() += windowFrameMargins->top(); } bar.subControls = QStyle::SC_TitleBarCloseButton; if (q->style()->subControlRect(QStyle::CC_TitleBar, &bar, @@ -669,8 +663,8 @@ void QGraphicsWidgetPrivate::windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent QStyleOptionTitleBar bar; // make sure that the coordinates (rect and pos) we send to the style are positive. if (windowFrameMargins) { - pos.rx() += windowFrameMargins[Left]; - pos.ry() += windowFrameMargins[Top]; + pos.rx() += windowFrameMargins->left(); + pos.ry() += windowFrameMargins->top(); } initStyleOptionTitleBar(&bar); bar.rect = q->windowFrameRect().toRect(); diff --git a/src/widgets/graphicsview/qgraphicswidget_p.h b/src/widgets/graphicsview/qgraphicswidget_p.h index 821f8c73f1..5e0fdb693b 100644 --- a/src/widgets/graphicsview/qgraphicswidget_p.h +++ b/src/widgets/graphicsview/qgraphicswidget_p.h @@ -60,6 +60,8 @@ #include #include +#include + QT_REQUIRE_CONFIG(graphicsview); QT_BEGIN_NAMESPACE @@ -78,8 +80,7 @@ public: qreal titleBarHeight(const QStyleOptionTitleBar &options) const; // Margins - enum {Left, Top, Right, Bottom}; - mutable qreal *margins; + mutable std::unique_ptr margins; void ensureMargins() const; void fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *oldScene, QGraphicsScene *newScene = nullptr); @@ -193,7 +194,7 @@ public: void ensureWindowData(); bool setWindowFrameMargins; - mutable qreal *windowFrameMargins; + mutable std::unique_ptr windowFrameMargins; void ensureWindowFrameMargins() const; #ifndef QT_NO_ACTION -- cgit v1.2.3