diff options
32 files changed, 594 insertions, 455 deletions
@@ -771,7 +771,7 @@ setBootstrapVariable() echo "RM_RF = rm -rf" >> "$mkfile" case `basename "$PLATFORM"` in - win32-g++*) + win32-*g++*) cat "$in_mkfile.win32" >> "$mkfile" ;; *) diff --git a/configure.json b/configure.json index 85d6a8c31a..3702c24f63 100644 --- a/configure.json +++ b/configure.json @@ -730,6 +730,7 @@ "headersclean": { "label": "Check for clean headers", "autoDetect": "features.developer-build", + "condition": "!config.wasm", "output": [ "privateConfig" ] }, "framework": { diff --git a/configure.pri b/configure.pri index 3747f96f3d..64ed6b9ed8 100644 --- a/configure.pri +++ b/configure.pri @@ -1221,13 +1221,43 @@ defineReplace(qtConfReportArch) { return("$$arch, CPU features: $$subarch") } +defineReplace(qtConfReportCompiler) { + clang_cl: { + return("clang-cl $${QMAKE_CLANG_MAJOR_VERSION}.$${QMAKE_CLANG_MINOR_VERSION}.$${QMAKE_CLANG_PATCH_VERSION}") + } else: clang { + !isEmpty(QMAKE_APPLE_CLANG_MAJOR_VERSION) { + return("clang (Apple) $${QMAKE_APPLE_CLANG_MAJOR_VERSION}.$${QMAKE_APPLE_CLANG_MINOR_VERSION}.$${QMAKE_APPLE_CLANG_PATCH_VERSION}") + } else { + return("clang $${QMAKE_CLANG_MAJOR_VERSION}.$${QMAKE_CLANG_MINOR_VERSION}.$${QMAKE_CLANG_PATCH_VERSION}") + } + } else: intel_icc { + return("intel_icc $$QMAKE_ICC_VER") + } else: intel_icl { + return("intel_icl $$QMAKE_ICC_VER") + } else: rim_qcc { + return("rim_qcc $${QMAKE_GCC_MAJOR_VERSION}.$${QMAKE_GCC_MINOR_VERSION}.$${QMAKE_GCC_PATCH_VERSION}") + } else: gcc { + return("gcc $${QMAKE_GCC_MAJOR_VERSION}.$${QMAKE_GCC_MINOR_VERSION}.$${QMAKE_GCC_PATCH_VERSION}") + } else: msvc { + return("msvc $$QMAKE_MSC_FULL_VER") + } else: ghs { + return("ghs $$QMAKE_GHS_VERSION") + } else { + return("unknown ($$QMAKE_COMPILER)") + } +} + + defineTest(qtConfReport_buildTypeAndConfig) { !$$qtConfEvaluate("features.cross_compile") { qtConfAddReport("Build type: $$[QMAKE_SPEC] ($$qtConfReportArch(architecture))") + qtConfAddReport("Compiler: $$qtConfReportCompiler()") } else { qtConfAddReport("Building on: $$[QMAKE_SPEC] ($$qtConfReportArch(host_architecture))") qtConfAddReport("Building for: $$[QMAKE_XSPEC] ($$qtConfReportArch(architecture))") + qtConfAddReport("Target compiler: $$qtConfReportCompiler()") } + qtConfAddReport() qtConfAddReport("Configuration: $$eval($${currentConfig}.output.privatePro.append.CONFIG) $$eval($${currentConfig}.output.publicPro.append.QT_CONFIG)") qtConfAddReport() diff --git a/examples/network/network.pro b/examples/network/network.pro index 93049014eb..1556e26ab1 100644 --- a/examples/network/network.pro +++ b/examples/network/network.pro @@ -29,12 +29,8 @@ qtHaveModule(widgets) { } - qtConfig(openssl) { - SUBDIRS += \ - securesocketclient \ - secureudpserver \ - secureudpclient - } + qtConfig(openssl): SUBDIRS += securesocketclient + qtConfig(dtls): SUBDIRS += secureudpserver secureudpclient qtConfig(sctp): SUBDIRS += multistreamserver multistreamclient } diff --git a/mkspecs/android-clang/qmake.conf b/mkspecs/android-clang/qmake.conf index b665000d00..1f5e690329 100644 --- a/mkspecs/android-clang/qmake.conf +++ b/mkspecs/android-clang/qmake.conf @@ -40,7 +40,11 @@ QMAKE_CFLAGS += -DANDROID_HAS_WSTRING --sysroot=$$NDK_ROOT/sysroot \ ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/llvm-libc++/libs/$$ANDROID_TARGET_ARCH ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++_shared.so -ANDROID_CXX_STL_LIBS = -lc++ + +exists($$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so): \ + ANDROID_CXX_STL_LIBS = -lc++ +else: \ + ANDROID_CXX_STL_LIBS = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so.$$replace(ANDROID_PLATFORM, "android-", "") QMAKE_CFLAGS_OPTIMIZE_SIZE = -Oz diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 409062cf49..7fd9dd9623 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -907,9 +907,9 @@ Platform-specific variables follow the naming pattern of the variables which they extend or modify, but include the name of the relevant - platform in their name. For example, \c QMAKE_LIBS can be used to specify a list - of libraries that a project needs to link against, and \c QMAKE_LIBS_X11 can be - used to extend or override this list. + platform in their name. For example, a makespec may use \c QMAKE_LIBS + to specify a list of libraries that each project needs to link against, + and \c QMAKE_LIBS_X11 would be used to extend this list. \target CONFIG \section1 CONFIG @@ -1320,6 +1320,19 @@ \snippet code/doc_src_qmake-manual.pro 39 + \target LIBS_PRIVATE + \section1 LIBS_PRIVATE + + Specifies a list of libraries to be linked privately into the project. + The behavior of this variable is identical to \l LIBS, except that + shared library projects built for Unix do not expose these dependencies + in their link interface. + + The effect of this is that if project C depends on library B which + depends on library A privately, but C also wants to use symbols from A + directly, it needs to link to A explicitly. Put differently, libraries + linked privately are not exposed transitively at build time. + \target LITERAL_HASH \section1 LITERAL_HASH @@ -2048,7 +2061,19 @@ \section1 QMAKE_LIBDIR - Specifies a list of system library paths. + Specifies a list of library search paths for all projects. + The value of this variable is typically handled by qmake + or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + + To specify additional search paths in project files, + use \l LIBS like that, instead: + \badcode + LIBS += -L/path/to/libraries + \endcode + + \section1 QMAKE_LIBDIR_POST + + Specifies a list of system library search paths for all projects. The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. @@ -2098,10 +2123,22 @@ \section1 QMAKE_LIBS - Specifies all project libraries. The value of this variable - is typically handled by qmake or + Specifies additional libraries each project needs to link against. + The value of this variable is typically handled by qmake or + \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + + To specify libraries in a project file, use \l LIBS instead. + + \section1 QMAKE_LIBS_PRIVATE + + Specifies additional private libraries each project needs to + link against. + The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + To specify private libraries in a library project file, + use \l LIBS_PRIVATE instead. + \section1 QMAKE_LIBS_EGL Specifies all EGL libraries when building Qt with OpenGL/ES diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index 72daa97fe4..5407ed6c69 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -829,7 +829,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) if(!project->isActiveConfig("staticlib")) { //DUMP LIBRARIES ProStringList &libdirs = project->values("QMAKE_PBX_LIBPATHS"), &frameworkdirs = project->values("QMAKE_FRAMEWORKPATH"); - static const char * const libs[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; + static const char * const libs[] = { "LIBS", "LIBS_PRIVATE", + "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; libs[i]; i++) { tmp = project->values(libs[i]); for(int x = 0; x < tmp.count();) { @@ -1695,6 +1696,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) t << "\t\t\t\t" << writeSettings("OTHER_LDFLAGS", fixListForOutput("SUBLIBS") + fixListForOutput("QMAKE_LFLAGS") + + fixListForOutput(fixLibFlags("LIBS")) + + fixListForOutput(fixLibFlags("LIBS_PRIVATE")) + fixListForOutput(fixLibFlags("QMAKE_LIBS")) + fixListForOutput(fixLibFlags("QMAKE_LIBS_PRIVATE")), SettingsAsList, 6) << ";\n"; diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 7c359071bf..e41e391cad 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -1012,12 +1012,10 @@ MakefileGenerator::writePrlFile(QTextStream &t) t << "QMAKE_PRL_VERSION = " << project->first("VERSION") << endl; if(project->isActiveConfig("staticlib") || project->isActiveConfig("explicitlib")) { ProStringList libs; - if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) - libs = project->values("QMAKE_INTERNAL_PRL_LIBS"); + if (!project->isActiveConfig("staticlib")) + libs << "LIBS" << "QMAKE_LIBS"; else - libs << "QMAKE_LIBS"; //obvious one - if(project->isActiveConfig("staticlib")) - libs << "QMAKE_LIBS_PRIVATE"; + libs << "LIBS" << "LIBS_PRIVATE" << "QMAKE_LIBS" << "QMAKE_LIBS_PRIVATE"; t << "QMAKE_PRL_LIBS ="; for (ProStringList::Iterator it = libs.begin(); it != libs.end(); ++it) t << qv(project->values((*it).toKey())); @@ -3348,10 +3346,9 @@ MakefileGenerator::writePkgConfigFile() if (project->isActiveConfig("staticlib")) { ProStringList libs; - if (!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) - libs = project->values("QMAKE_INTERNAL_PRL_LIBS"); - else - libs << "QMAKE_LIBS"; //obvious one + libs << "LIBS"; // FIXME: this should not be conditional on staticlib + libs << "LIBS_PRIVATE"; + libs << "QMAKE_LIBS"; // FIXME: this should not be conditional on staticlib libs << "QMAKE_LIBS_PRIVATE"; libs << "QMAKE_LFLAGS_THREAD"; //not sure about this one, but what about things like -pthread? t << "Libs.private:"; diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index 4fe1a54501..50ec8db79e 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -37,6 +37,17 @@ QT_BEGIN_NAMESPACE +ProStringList UnixMakefileGenerator::libdirToFlags(const ProKey &key) +{ + ProStringList results; + for (const auto &libdir : qAsConst(project->values(key))) { + if (!project->isEmpty("QMAKE_LFLAGS_RPATH") && project->isActiveConfig("rpath_libdirs")) + project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATH") + libdir; + results.append("-L" + escapeFilePath(libdir)); + } + return results; +} + void UnixMakefileGenerator::init() { @@ -80,8 +91,6 @@ UnixMakefileGenerator::init() } project->values("QMAKE_ORIG_DESTDIR") = project->values("DESTDIR"); - project->values("QMAKE_LIBS") += project->values("LIBS"); - project->values("QMAKE_LIBS_PRIVATE") += project->values("LIBS_PRIVATE"); if((!project->isEmpty("QMAKE_LIB_FLAG") && !project->isActiveConfig("staticlib")) || (project->isActiveConfig("qt") && project->isActiveConfig("plugin"))) { if(configs.indexOf("dll") == -1) configs.append("dll"); @@ -95,21 +104,13 @@ UnixMakefileGenerator::init() project->isActiveConfig("dll")) project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_PREBIND"); project->values("QMAKE_INCDIR") += project->values("QMAKE_INCDIR_POST"); - project->values("QMAKE_LIBDIR") += project->values("QMAKE_LIBDIR_POST"); project->values("QMAKE_RPATHDIR") += project->values("QMAKE_RPATHDIR_POST"); project->values("QMAKE_RPATHLINKDIR") += project->values("QMAKE_RPATHLINKDIR_POST"); if(!project->isEmpty("QMAKE_INCDIR")) project->values("INCLUDEPATH") += project->values("QMAKE_INCDIR"); - ProStringList ldadd; - if(!project->isEmpty("QMAKE_LIBDIR")) { - const ProStringList &libdirs = project->values("QMAKE_LIBDIR"); - for(int i = 0; i < libdirs.size(); ++i) { - if(!project->isEmpty("QMAKE_LFLAGS_RPATH") && project->isActiveConfig("rpath_libdirs")) - project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATH") + libdirs[i]; - project->values("QMAKE_LIBDIR_FLAGS") += "-L" + escapeFilePath(libdirs[i]); - } - } - ldadd += project->values("QMAKE_LIBDIR_FLAGS"); + // The order of the next two lines is relevant due to side effect on QMAKE_LFLAGS. + ProStringList ldadd = project->values("QMAKE_LIBDIR_FLAGS") + libdirToFlags("QMAKE_LIBDIR"); + ProStringList ldaddpost = libdirToFlags("QMAKE_LIBDIR_POST"); if (project->isActiveConfig("mac")) { if (!project->isEmpty("QMAKE_FRAMEWORKPATH")) { const ProStringList &fwdirs = project->values("QMAKE_FRAMEWORKPATH"); @@ -118,8 +119,10 @@ UnixMakefileGenerator::init() } ldadd += project->values("QMAKE_FRAMEWORKPATH_FLAGS"); } - ProStringList &qmklibs = project->values("QMAKE_LIBS"); + ProStringList &qmklibs = project->values("LIBS"); qmklibs = ldadd + qmklibs; + ProStringList &qmklibspost = project->values("QMAKE_LIBS"); + qmklibspost = ldaddpost + qmklibspost; if (!project->isEmpty("QMAKE_RPATHDIR") && !project->isEmpty("QMAKE_LFLAGS_RPATH")) { const ProStringList &rpathdirs = project->values("QMAKE_RPATHDIR"); for (int i = 0; i < rpathdirs.size(); ++i) { @@ -300,35 +303,11 @@ UnixMakefileGenerator::init() } init2(); - project->values("QMAKE_INTERNAL_PRL_LIBS") << "QMAKE_LIBS"; ProString target = project->first("TARGET"); int slsh = target.lastIndexOf(Option::dir_sep); if (slsh != -1) target.chopFront(slsh + 1); project->values("LIB_TARGET").prepend(target); - if(!project->isEmpty("QMAKE_MAX_FILES_PER_AR")) { - bool ok; - int max_files = project->first("QMAKE_MAX_FILES_PER_AR").toInt(&ok); - ProStringList ar_sublibs, objs = project->values("OBJECTS"); - if(ok && max_files > 5 && max_files < (int)objs.count()) { - QString lib; - for(int i = 0, obj_cnt = 0, lib_cnt = 0; i != objs.size(); ++i) { - if((++obj_cnt) >= max_files) { - if(lib_cnt) { - lib.sprintf("lib%s-tmp%d.a", - project->first("QMAKE_ORIG_TARGET").toLatin1().constData(), lib_cnt); - ar_sublibs << lib; - obj_cnt = 0; - } - lib_cnt++; - } - } - } - if(!ar_sublibs.isEmpty()) { - project->values("QMAKE_AR_SUBLIBS") = ar_sublibs; - project->values("QMAKE_INTERNAL_PRL_LIBS") << "QMAKE_AR_SUBLIBS"; - } - } } QStringList @@ -420,7 +399,8 @@ UnixMakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags) libdirs.append(QMakeLocalFileName(dlib.toQString())); frameworkdirs.append(QMakeLocalFileName("/System/Library/Frameworks")); frameworkdirs.append(QMakeLocalFileName("/Library/Frameworks")); - static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; + static const char * const lflags[] = { "LIBS", "LIBS_PRIVATE", + "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; lflags[i]; i++) { ProStringList &l = project->values(lflags[i]); for (ProStringList::Iterator it = l.begin(); it != l.end(); ) { diff --git a/qmake/generators/unix/unixmake.h b/qmake/generators/unix/unixmake.h index c5e42aa1ae..5b0766855b 100644 --- a/qmake/generators/unix/unixmake.h +++ b/qmake/generators/unix/unixmake.h @@ -66,6 +66,7 @@ protected: private: void init2(); + ProStringList libdirToFlags(const ProKey &key); }; inline UnixMakefileGenerator::~UnixMakefileGenerator() diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index ab946fa439..976751b02c 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -213,7 +213,9 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) if(!project->isActiveConfig("staticlib")) { t << "LINK = " << var("QMAKE_LINK") << endl; t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl; - t << "LIBS = $(SUBLIBS) " << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' + t << "LIBS = $(SUBLIBS) " << fixLibFlags("LIBS").join(' ') << ' ' + << fixLibFlags("LIBS_PRIVATE").join(' ') << ' ' + << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' << fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << endl; } @@ -690,56 +692,20 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) QString destdir_r = project->first("DESTDIR").toQString(); QString destdir_d = escapeDependencyPath(destdir_r); QString destdir = escapeFilePath(destdir_r); - allDeps = ' ' + destdir_d + depVar("TARGET") - + varGlue("QMAKE_AR_SUBLIBS", ' ' + destdir_d, ' ' + destdir_d, ""); - t << "staticlib: " << destdir_d << "$(TARGET)\n\n"; - if(project->isEmpty("QMAKE_AR_SUBLIBS")) { - t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") - << " $(OBJECTS) $(OBJCOMP) " << depVar("POST_TARGETDEPS") << "\n\t"; - if(!destdir.isEmpty()) - t << mkdir_p_asstring(destdir, false) << "\n\t"; - if (!project->isEmpty("QMAKE_PRE_LINK")) - t << var("QMAKE_PRE_LINK") << "\n\t"; - t << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t" - << var("QMAKE_AR_CMD") << "\n"; - if(!project->isEmpty("QMAKE_POST_LINK")) - t << "\t" << var("QMAKE_POST_LINK") << "\n"; - if(!project->isEmpty("QMAKE_RANLIB")) - t << "\t$(RANLIB) " << destdir << "$(TARGET)\n"; - } else { - int max_files = project->first("QMAKE_MAX_FILES_PER_AR").toInt(); - ProStringList objs = project->values("OBJECTS") + project->values("OBJCOMP"), - libs = project->values("QMAKE_AR_SUBLIBS"); - libs.prepend("$(TARGET)"); - for (ProStringList::Iterator libit = libs.begin(), objit = objs.begin(); - libit != libs.end(); ++libit) { - ProStringList build; - for(int cnt = 0; cnt < max_files && objit != objs.end(); ++objit, cnt++) - build << (*objit); - QString ar; - ProString lib = destdir + escapeFilePath(*libit); - if((*libit) == "$(TARGET)") { - t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") - << ' ' << depVar("POST_TARGETDEPS") << valList(escapeDependencyPaths(build)) << "\n\t"; - ar = project->first("QMAKE_AR_CMD").toQString(); - ar.replace(QLatin1String("$(OBJECTS)"), escapeFilePaths(build).join(' ')); - } else { - t << destdir_d << escapeDependencyPath(*libit) << ": " - << valList(escapeDependencyPaths(build)) << "\n\t"; - ar = "$(AR) " + lib + ' ' + escapeFilePaths(build).join(' '); - } - if(!destdir.isEmpty()) - t << mkdir_p_asstring(destdir, false) << "\n\t"; - if (!project->isEmpty("QMAKE_PRE_LINK")) - t << var("QMAKE_PRE_LINK") << "\n\t"; - t << "-$(DEL_FILE) " << lib << "\n\t" - << ar << "\n"; - if(!project->isEmpty("QMAKE_POST_LINK")) - t << "\t" << var("QMAKE_POST_LINK") << "\n"; - if(!project->isEmpty("QMAKE_RANLIB")) - t << "\t$(RANLIB) " << lib << "\n"; - } - } + allDeps = ' ' + destdir_d + depVar("TARGET"); + t << "staticlib: " << destdir_d << "$(TARGET)\n\n" + << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") + << " $(OBJECTS) $(OBJCOMP) " << depVar("POST_TARGETDEPS") << "\n\t"; + if (!destdir.isEmpty()) + t << mkdir_p_asstring(destdir, false) << "\n\t"; + if (!project->isEmpty("QMAKE_PRE_LINK")) + t << var("QMAKE_PRE_LINK") << "\n\t"; + t << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t" + << var("QMAKE_AR_CMD") << "\n"; + if (!project->isEmpty("QMAKE_POST_LINK")) + t << "\t" << var("QMAKE_POST_LINK") << "\n"; + if (!project->isEmpty("QMAKE_RANLIB")) + t << "\t$(RANLIB) " << destdir << "$(TARGET)\n"; t << endl << endl; } @@ -1515,10 +1481,7 @@ UnixMakefileGenerator::writeLibtoolFile() t << "# Libraries that this one depends upon.\n"; ProStringList libs; - if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) - libs = project->values("QMAKE_INTERNAL_PRL_LIBS"); - else - libs << "QMAKE_LIBS"; //obvious one + libs << "LIBS" << "QMAKE_LIBS"; t << "dependency_libs='"; for (ProStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it) t << fixLibFlags((*it).toKey()).join(' ') << ' '; diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index 13412e971a..de7363e51b 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -131,22 +131,25 @@ QString MingwMakefileGenerator::installRoot() const return QStringLiteral("$(INSTALL_ROOT:@msyshack@%=%)"); } -void createLdObjectScriptFile(const QString &fileName, const ProStringList &objList) +void createLdResponseFile(const QString &fileName, const ProStringList &objList) { QString filePath = Option::output_dir + QDir::separator() + fileName; QFile file(filePath); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream t(&file); - t << "INPUT(\n"; for (ProStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) { QString path = (*it).toQString(); - // ### quoting? - if (QDir::isRelativePath(path)) - t << "./" << path << endl; - else - t << path << endl; + // In response files, whitespace and special characters are + // escaped with a backslash; backslashes themselves can either + // be escaped into double backslashes, or, as this is a list of + // path names, converted to forward slashes. + path.replace(QLatin1Char('\\'), QLatin1String("/")) + .replace(QLatin1Char(' '), QLatin1String("\\ ")) + .replace(QLatin1Char('\t'), QLatin1String("\\\t")) + .replace(QLatin1Char('"'), QLatin1String("\\\"")) + .replace(QLatin1Char('\''), QLatin1String("\\'")); + t << path << endl; } - t << ");\n"; t.flush(); file.close(); } @@ -206,7 +209,7 @@ void MingwMakefileGenerator::init() processVars(); - project->values("QMAKE_LIBS") += project->values("RES_FILE"); + project->values("LIBS") += project->values("RES_FILE"); if (project->isActiveConfig("dll")) { QString destDir = ""; @@ -282,6 +285,8 @@ void MingwMakefileGenerator::writeLibsPart(QTextStream &t) t << "LINKER = " << var("QMAKE_LINK") << endl; t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl; t << "LIBS = " + << fixLibFlags("LIBS").join(' ') << ' ' + << fixLibFlags("LIBS_PRIVATE").join(' ') << ' ' << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' << fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << endl; } @@ -307,14 +312,13 @@ void MingwMakefileGenerator::writeObjectsPart(QTextStream &t) createArObjectScriptFile(ar_script_file, var("DEST_TARGET"), project->values("OBJECTS")); objectsLinkLine = ar_cmd + " -M < " + escapeFilePath(ar_script_file); } else { - QString ld_script_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET"); - if (!var("BUILD_NAME").isEmpty()) { - ld_script_file += "." + var("BUILD_NAME"); - } + QString ld_response_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET"); + if (!var("BUILD_NAME").isEmpty()) + ld_response_file += "." + var("BUILD_NAME"); if (!var("MAKEFILE").isEmpty()) - ld_script_file += "." + var("MAKEFILE"); - createLdObjectScriptFile(ld_script_file, project->values("OBJECTS")); - objectsLinkLine = escapeFilePath(ld_script_file); + ld_response_file += "." + var("MAKEFILE"); + createLdResponseFile(ld_response_file, project->values("OBJECTS")); + objectsLinkLine = "@" + escapeFilePath(ld_response_file); } Win32MakefileGenerator::writeObjectsPart(t); } diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index fa7ee1b98a..f2cd7c633b 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -383,7 +383,7 @@ void NmakeMakefileGenerator::init() processVars(); - project->values("QMAKE_LIBS") += project->values("RES_FILE"); + project->values("LIBS") += project->values("RES_FILE"); if (!project->values("DEF_FILE").isEmpty()) { QString defFileName = fileFixify(project->first("DEF_FILE").toQString()); diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 73f0f35d1b..f7837fc1b4 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -457,9 +457,8 @@ ProStringList VcprojGenerator::collectDependencies(QMakeProject *proj, QHash<QSt newDep->dependencies << "idc.exe"; // Add all unknown libs to the deps - QStringList where = QStringList() << "QMAKE_LIBS" << "QMAKE_LIBS_PRIVATE"; - if (!tmp_proj.isEmpty("QMAKE_INTERNAL_PRL_LIBS")) - where = tmp_proj.values("QMAKE_INTERNAL_PRL_LIBS").toQStringList(); + QStringList where = QStringList() << "LIBS" << "LIBS_PRIVATE" + << "QMAKE_LIBS" << "QMAKE_LIBS_PRIVATE"; for (QStringList::ConstIterator wit = where.begin(); wit != where.end(); ++wit) { const ProStringList &l = tmp_proj.values(ProKey(*wit)); @@ -750,7 +749,7 @@ void VcprojGenerator::init() projectTarget = Application; } else if(project->first("TEMPLATE") == "vclib") { if(project->isActiveConfig("staticlib")) { - project->values("QMAKE_LIBS") += project->values("RES_FILE"); + project->values("LIBS") += project->values("RES_FILE"); projectTarget = StaticLib; } else projectTarget = SharedLib; @@ -1086,7 +1085,8 @@ void VcprojGenerator::initLinkerTool() if (!project->values("DEF_FILE").isEmpty()) conf.linker.ModuleDefinitionFile = project->first("DEF_FILE").toQString(); - static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; + static const char * const lflags[] = { "LIBS", "LIBS_PRIVATE", + "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; lflags[i]; i++) { const auto libs = fixLibFlags(lflags[i]); for (const ProString &lib : libs) { @@ -1181,7 +1181,8 @@ void VcprojGenerator::initDeploymentTool() if (!dllPaths.isEmpty() && !(conf.WinRT && project->first("MSVC_VER").toQString() == "14.0")) { // FIXME: This code should actually resolve the libraries from all Qt modules. - ProStringList arg = project->values("QMAKE_LIBS") + project->values("QMAKE_LIBS_PRIVATE"); + ProStringList arg = project->values("LIBS") + project->values("LIBS_PRIVATE") + + project->values("QMAKE_LIBS") + project->values("QMAKE_LIBS_PRIVATE"); bool qpaPluginDeployed = false; for (ProStringList::ConstIterator it = arg.constBegin(); it != arg.constEnd(); ++it) { QString dllName = (*it).toQString(); diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index 1388e120e7..e0d03ccc1c 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -84,7 +84,8 @@ Win32MakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags) if (impexts.isEmpty()) impexts = project->values("QMAKE_EXTENSION_STATICLIB"); QList<QMakeLocalFileName> dirs; - static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; + static const char * const lflags[] = { "LIBS", "LIBS_PRIVATE", + "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; lflags[i]; i++) { ProStringList &l = project->values(lflags[i]); for (ProStringList::Iterator it = l.begin(); it != l.end();) { @@ -225,8 +226,8 @@ void Win32MakefileGenerator::processVars() libs << QLatin1String("-L") + lib; } } - project->values("QMAKE_LIBS") += libs + project->values("LIBS"); - project->values("QMAKE_LIBS_PRIVATE") += project->values("LIBS_PRIVATE"); + ProStringList &qmklibs = project->values("LIBS"); + qmklibs = libs + qmklibs; if (project->values("TEMPLATE").contains("app")) { project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_APP"); @@ -651,7 +652,9 @@ void Win32MakefileGenerator::writeLibsPart(QTextStream &t) } else { t << "LINKER = " << var("QMAKE_LINK") << endl; t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl; - t << "LIBS = " << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' + t << "LIBS = " << fixLibFlags("LIBS").join(' ') << ' ' + << fixLibFlags("LIBS_PRIVATE").join(' ') << ' ' + << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' << fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << endl; } } diff --git a/src/3rdparty/freetype/qt_attribution.json b/src/3rdparty/freetype/qt_attribution.json index 4be86e92b6..f46541cf2e 100644 --- a/src/3rdparty/freetype/qt_attribution.json +++ b/src/3rdparty/freetype/qt_attribution.json @@ -7,6 +7,8 @@ "Description": "FreeType is a freely available software library to render fonts.", "Homepage": "http://www.freetype.org", + "Version": "2.6.1", + "License": "Freetype Project License or GNU General Public License v2.0 only", "LicenseId": "FTL OR GPL-2.0", "LicenseFile": "LICENSE.txt", diff --git a/src/3rdparty/wasm/qt_attribution.json b/src/3rdparty/wasm/qt_attribution.json index 184e2968cd..2724008157 100644 --- a/src/3rdparty/wasm/qt_attribution.json +++ b/src/3rdparty/wasm/qt_attribution.json @@ -18,4 +18,3 @@ "LicenseFile": "LICENSE", "Copyright": "Copyright (C) 2003 Bitstream,Inc" } - diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 8a4c6b7fda..636cacfb9c 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -1454,7 +1454,8 @@ void QImage::setDevicePixelRatio(qreal scaleFactor) return; detach(); - d->devicePixelRatio = scaleFactor; + if (d) + d->devicePixelRatio = scaleFactor; } /*! @@ -2240,8 +2241,15 @@ bool QImage::reinterpretAsFormat(Format format) return true; if (qt_depthForFormat(format) != qt_depthForFormat(d->format)) return false; - if (!isDetached()) // Detach only if shared, not for read-only data. + if (!isDetached()) { // Detach only if shared, not for read-only data. + QImageData *oldD = d; detach(); + // In case detach() ran out of memory + if (!d) { + d = oldD; + return false; + } + } d->format = format; return true; @@ -3288,6 +3296,8 @@ void QImage::mirrored_inplace(bool horizontal, bool vertical) return; detach(); + if (!d) + return; if (!d->own_data) *this = copy(); @@ -3440,6 +3450,8 @@ void QImage::rgbSwapped_inplace() return; detach(); + if (!d) + return; if (!d->own_data) *this = copy(); diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index e1f66dceee..964dc0d5c6 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -119,6 +119,7 @@ void qGamma_correct_back_to_linear_cs(QImage *image) *****************************************************************************/ // The drawhelper conversions from/to RGB32 are passthroughs which is not always correct for general image conversion +#if !defined(__ARM_NEON__) static void QT_FASTCALL storeRGB32FromARGB32PM(uchar *dest, const uint *src, int index, int count, const QVector<QRgb> *, QDitherInfo *) { @@ -126,6 +127,7 @@ static void QT_FASTCALL storeRGB32FromARGB32PM(uchar *dest, const uint *src, int for (int i = 0; i < count; ++i) d[i] = 0xff000000 | qUnpremultiply(src[i]); } +#endif static void QT_FASTCALL storeRGB32FromARGB32(uchar *dest, const uint *src, int index, int count, const QVector<QRgb> *, QDitherInfo *) @@ -147,6 +149,9 @@ static const uint *QT_FASTCALL fetchRGB32ToARGB32PM(uint *buffer, const uchar *s #ifdef QT_COMPILER_SUPPORTS_SSE4_1 extern void QT_FASTCALL storeRGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, const QVector<QRgb> *, QDitherInfo *); +#elif defined(__ARM_NEON__) +extern void QT_FASTCALL storeRGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); #endif void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags) @@ -175,8 +180,12 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio if (qCpuHasFeature(SSE4_1)) store = storeRGB32FromARGB32PM_sse4; else -#endif store = storeRGB32FromARGB32PM; +#elif defined(__ARM_NEON__) + store = storeRGB32FromARGB32PM_neon; +#else + store = storeRGB32FromARGB32PM; +#endif } } if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied && @@ -261,8 +270,12 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im if (qCpuHasFeature(SSE4_1)) store = storeRGB32FromARGB32PM_sse4; else -#endif store = storeRGB32FromARGB32PM; +#elif defined(__ARM_NEON__) + store = storeRGB32FromARGB32PM_neon; +#else + store = storeRGB32FromARGB32PM; +#endif } } if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied && diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp index a9e472f8c4..b8d13ac092 100644 --- a/src/gui/image/qpixmap_win.cpp +++ b/src/gui/image/qpixmap_win.cpp @@ -449,8 +449,7 @@ Q_GUI_EXPORT QImage qt_imageFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0 Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0) { - const QImage image = imageFromWinHBITMAP_GetDiBits(bitmap, /* forceQuads */ true, hbitmapFormat); - return QPixmap::fromImage(image); + return QPixmap::fromImage(imageFromWinHBITMAP_GetDiBits(bitmap, /* forceQuads */ true, hbitmapFormat)); } Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &p) @@ -567,7 +566,7 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon) SelectObject(hdc, oldhdc); //restore state DeleteObject(winBitmap); DeleteDC(hdc); - return QPixmap::fromImage(image); + return QPixmap::fromImage(std::move(image)); } QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 0264059a5c..bbeb9fd9ea 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -6505,10 +6505,19 @@ static void qInitDrawhelperFunctions() const QVector<QRgb> *, QDitherInfo *); extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_neon(uint *buffer, const uchar *src, int index, int count, const QVector<QRgb> *, QDitherInfo *); + extern void QT_FASTCALL storeARGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); + extern void QT_FASTCALL storeRGBA8888FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); + extern void QT_FASTCALL storeRGBXFromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *); qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_neon; qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_neon; + qPixelLayouts[QImage::Format_ARGB32].storeFromARGB32PM = storeARGB32FromARGB32PM_neon; qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_neon; qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_neon; + qPixelLayouts[QImage::Format_RGBA8888].storeFromARGB32PM = storeRGBA8888FromARGB32PM_neon; + qPixelLayouts[QImage::Format_RGBX8888].storeFromARGB32PM = storeRGBXFromARGB32PM_neon; #endif #if defined(ENABLE_PIXMAN_DRAWHELPERS) diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 98995f485a..629dfe2358 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -1081,15 +1081,28 @@ const uint * QT_FASTCALL qt_fetchUntransformed_888_neon(uint *buffer, const Oper } #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -template<bool RGBA> -static inline void convertARGBToARGB32PM_neon(uint *buffer, const uint *src, int count) +static inline uint32x4_t vrgba2argb(uint32x4_t srcVector) { - int i = 0; #if defined(Q_PROCESSOR_ARM_64) const uint8x16_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15}; #else const uint8x8_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7 }; #endif +#if defined(Q_PROCESSOR_ARM_64) + srcVector = vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(srcVector), rgbaMask)); +#else + // no vqtbl1q_u8, so use two vtbl1_u8 + const uint8x8_t low = vtbl1_u8(vreinterpret_u8_u32(vget_low_u32(srcVector)), rgbaMask); + const uint8x8_t high = vtbl1_u8(vreinterpret_u8_u32(vget_high_u32(srcVector)), rgbaMask); + srcVector = vcombine_u32(vreinterpret_u32_u8(low), vreinterpret_u32_u8(high)); +#endif + return srcVector; +} + +template<bool RGBA> +static inline void convertARGBToARGB32PM_neon(uint *buffer, const uint *src, int count) +{ + int i = 0; const uint8x8_t shuffleMask = { 3, 3, 3, 3, 7, 7, 7, 7}; const uint32x4_t blendMask = vdupq_n_u32(0xff000000); @@ -1105,16 +1118,8 @@ static inline void convertARGBToARGB32PM_neon(uint *buffer, const uint *src, int #endif if (alphaSum) { if (alphaSum != 255 * 4) { - if (RGBA) { -#if defined(Q_PROCESSOR_ARM_64) - srcVector = vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(srcVector), rgbaMask)); -#else - // no vqtbl1q_u8 - const uint8x8_t low = vtbl1_u8(vreinterpret_u8_u32(vget_low_u32(srcVector)), rgbaMask); - const uint8x8_t high = vtbl1_u8(vreinterpret_u8_u32(vget_high_u32(srcVector)), rgbaMask); - srcVector = vcombine_u32(vreinterpret_u32_u8(low), vreinterpret_u32_u8(high)); -#endif - } + if (RGBA) + srcVector = vrgba2argb(srcVector); const uint8x8_t s1 = vreinterpret_u8_u32(vget_low_u32(srcVector)); const uint8x8_t s2 = vreinterpret_u8_u32(vget_high_u32(srcVector)); const uint8x8_t alpha1 = vtbl1_u8(s1, shuffleMask); @@ -1128,19 +1133,10 @@ static inline void convertARGBToARGB32PM_neon(uint *buffer, const uint *src, int const uint32x4_t d = vbslq_u32(blendMask, srcVector, vreinterpretq_u32_u8(vcombine_u8(d1, d2))); vst1q_u32(buffer + i, d); } else { - if (RGBA) { -#if defined(Q_PROCESSOR_ARM_64) - srcVector = vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(srcVector), rgbaMask)); -#else - // no vqtbl1q_u8 - const uint8x8_t low = vtbl1_u8(vreinterpret_u8_u32(vget_low_u32(srcVector)), rgbaMask); - const uint8x8_t high = vtbl1_u8(vreinterpret_u8_u32(vget_high_u32(srcVector)), rgbaMask); - srcVector = vcombine_u32(vreinterpret_u32_u8(low), vreinterpret_u32_u8(high)); -#endif - vst1q_u32(buffer + i, srcVector); - } else if (buffer != src) { + if (RGBA) + vst1q_u32(buffer + i, vrgba2argb(srcVector)); + else if (buffer != src) vst1q_u32(buffer + i, srcVector); - } } } else { vst1q_u32(buffer + i, vdupq_n_u32(0)); @@ -1153,6 +1149,91 @@ static inline void convertARGBToARGB32PM_neon(uint *buffer, const uint *src, int } } +static inline float32x4_t reciprocal_mul_ps(float32x4_t a, float mul) +{ + float32x4_t ia = vrecpeq_f32(a); // estimate 1/a + ia = vmulq_f32(vrecpsq_f32(a, ia), vmulq_n_f32(ia, mul)); // estimate improvement step * mul + return ia; +} + +template<bool RGBA, bool RGBx> +static inline void convertARGBFromARGB32PM_neon(uint *buffer, const uint *src, int count) +{ + int i = 0; + const uint32x4_t alphaMask = vdupq_n_u32(0xff000000); + + for (; i < count - 3; i += 4) { + uint32x4_t srcVector = vld1q_u32(src + i); + uint32x4_t alphaVector = vshrq_n_u32(srcVector, 24); +#if defined(Q_PROCESSOR_ARM_64) + uint32_t alphaSum = vaddvq_u32(alphaVector); +#else + // no vaddvq_u32 + uint32x2_t tmp = vpadd_u32(vget_low_u32(alphaVector), vget_high_u32(alphaVector)); + uint32_t alphaSum = vget_lane_u32(vpadd_u32(tmp, tmp), 0); +#endif + if (alphaSum) { + if (alphaSum != 255 * 4) { + if (RGBA) + srcVector = vrgba2argb(srcVector); + const float32x4_t a = vcvtq_f32_u32(alphaVector); + const float32x4_t ia = reciprocal_mul_ps(a, 255.0f); + // Convert 4x(4xU8) to 4x(4xF32) + uint16x8_t tmp1 = vmovl_u8(vget_low_u8(vreinterpretq_u8_u32(srcVector))); + uint16x8_t tmp3 = vmovl_u8(vget_high_u8(vreinterpretq_u8_u32(srcVector))); + float32x4_t src1 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(tmp1))); + float32x4_t src2 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(tmp1))); + float32x4_t src3 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(tmp3))); + float32x4_t src4 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(tmp3))); + src1 = vmulq_lane_f32(src1, vget_low_f32(ia), 0); + src2 = vmulq_lane_f32(src2, vget_low_f32(ia), 1); + src3 = vmulq_lane_f32(src3, vget_high_f32(ia), 0); + src4 = vmulq_lane_f32(src4, vget_high_f32(ia), 1); + // Convert 4x(4xF32) back to 4x(4xU8) (over a 8.1 fixed point format to get rounding) + tmp1 = vcombine_u16(vrshrn_n_u32(vcvtq_n_u32_f32(src1, 1), 1), + vrshrn_n_u32(vcvtq_n_u32_f32(src2, 1), 1)); + tmp3 = vcombine_u16(vrshrn_n_u32(vcvtq_n_u32_f32(src3, 1), 1), + vrshrn_n_u32(vcvtq_n_u32_f32(src4, 1), 1)); + uint32x4_t dstVector = vreinterpretq_u32_u8(vcombine_u8(vmovn_u16(tmp1), vmovn_u16(tmp3))); + // Overwrite any undefined results from alpha==0 with zeros: +#if defined(Q_PROCESSOR_ARM_64) + uint32x4_t srcVectorAlphaMask = vceqzq_u32(alphaVector); +#else + uint32x4_t srcVectorAlphaMask = vceqq_u32(alphaVector, vdupq_n_u32(0)); +#endif + dstVector = vbicq_u32(dstVector, srcVectorAlphaMask); + // Restore or mask alpha values: + if (RGBx) + dstVector = vorrq_u32(alphaMask, dstVector); + else + dstVector = vbslq_u32(alphaMask, srcVector, dstVector); + vst1q_u32(&buffer[i], dstVector); + } else { + // 4xAlpha==255, no change except if we are doing RGBA->ARGB: + if (RGBA) + vst1q_u32(&buffer[i], vrgba2argb(srcVector)); + else if (buffer != src) + vst1q_u32(&buffer[i], srcVector); + } + } else { + // 4xAlpha==0, always zero, except if output is RGBx: + if (RGBx) + vst1q_u32(&buffer[i], alphaMask); + else + vst1q_u32(&buffer[i], vdupq_n_u32(0)); + } + } + + SIMD_EPILOGUE(i, count, 3) { + uint v = qUnpremultiply(src[i]); + if (RGBx) + v = 0xff000000 | v; + if (RGBA) + v = ARGB2RGBA(v); + buffer[i] = v; + } +} + void QT_FASTCALL convertARGB32ToARGB32PM_neon(uint *buffer, int count, const QVector<QRgb> *) { convertARGBToARGB32PM_neon<false>(buffer, buffer, count); @@ -1177,6 +1258,34 @@ const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_neon(uint *buffer, const uchar * return buffer; } +void QT_FASTCALL storeRGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + convertARGBFromARGB32PM_neon<false,true>(d, src, count); +} + +void QT_FASTCALL storeARGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + convertARGBFromARGB32PM_neon<false,false>(d, src, count); +} + +void QT_FASTCALL storeRGBA8888FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + convertARGBFromARGB32PM_neon<true,false>(d, src, count); +} + +void QT_FASTCALL storeRGBXFromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector<QRgb> *, QDitherInfo *) +{ + uint *d = reinterpret_cast<uint *>(dest) + index; + convertARGBFromARGB32PM_neon<true,true>(d, src, count); +} + #endif // Q_BYTE_ORDER == Q_LITTLE_ENDIAN QT_END_NAMESPACE diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp index 9c2ff8fb89..23ca62acd4 100644 --- a/src/network/access/qnetworkreplywasmimpl.cpp +++ b/src/network/access/qnetworkreplywasmimpl.cpp @@ -49,10 +49,135 @@ #include <private/qnetworkaccessmanager_p.h> #include <private/qnetworkfile_p.h> -#include <iostream> +#include <emscripten.h> +#include <emscripten/bind.h> +#include <emscripten/val.h> QT_BEGIN_NAMESPACE +using namespace emscripten; + +static void q_requestErrorCallback(val event) +{ + val xhr = event["target"]; + + quintptr func = xhr["data-handler"].as<quintptr>(); + QNetworkReplyWasmImplPrivate *reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(func); + Q_ASSERT(reply); + + int statusCode = xhr["status"].as<int>(); + + QString reasonStr = QString::fromStdString(xhr["statusText"].as<std::string>()); + + reply->setReplyAttributes(func, statusCode, reasonStr); + + if (statusCode >= 400 && !reasonStr.isEmpty()) + reply->emitReplyError(reply->statusCodeFromHttp(statusCode, reply->request.url()), reasonStr); +} + +static void q_progressCallback(val event) +{ + val xhr = event["target"]; + + QNetworkReplyWasmImplPrivate *reply = + reinterpret_cast<QNetworkReplyWasmImplPrivate*>(xhr["data-handler"].as<quintptr>()); + Q_ASSERT(reply); + + if (xhr["lengthComputable"].as<bool>() && xhr["status"].as<int>() < 400) + reply->emitDataReadProgress(xhr["loaded"].as<qint64>(), xhr["total"].as<qint64>()); + +} + +static void q_loadCallback(val event) +{ + val xhr = event["target"]; + + QNetworkReplyWasmImplPrivate *reply = + reinterpret_cast<QNetworkReplyWasmImplPrivate*>(xhr["data-handler"].as<quintptr>()); + Q_ASSERT(reply); + + int status = xhr["status"].as<int>(); + if (status >= 300) { + q_requestErrorCallback(event); + return; + } + QString statusText = QString::fromStdString(xhr["statusText"].as<std::string>()); + if (status == 200 || status == 203) { + QString responseString; + const std::string responseType = xhr["responseType"].as<std::string>(); + if (responseType.length() == 0 || responseType == "document" || responseType == "text") { + responseString = QString::fromStdWString(xhr["responseText"].as<std::wstring>()); + } else if (responseType == "json") { + responseString = + QString::fromStdWString(val::global("JSON").call<std::wstring>("stringify", xhr["response"])); + } else if (responseType == "arraybuffer" || responseType == "blob") { + // handle this data in the FileReader, triggered by the call to readAsArrayBuffer + val reader = val::global("FileReader").new_(); + reader.set("onload", val::module_property("QNetworkReplyWasmImplPrivate_readBinary")); + reader.set("data-handler", xhr["data-handler"]); + reader.call<void>("readAsArrayBuffer", xhr["response"]); + } + + int readyState = xhr["readyState"].as<int>(); + + if (readyState == 4) { // done + reply->setReplyAttributes(xhr["data-handler"].as<quintptr>(), status, statusText); + if (!responseString.isEmpty()) + reply->dataReceived(responseString.toUtf8(), responseString.size()); + } + } + if (status >= 400 && !statusText.isEmpty()) + reply->emitReplyError(reply->statusCodeFromHttp(status, reply->request.url()), statusText); +} + +static void q_responseHeadersCallback(val event) +{ + val xhr = event["target"]; + + if (xhr["readyState"].as<int>() == 2) { // HEADERS_RECEIVED + std::string responseHeaders = xhr.call<std::string>("getAllResponseHeaders"); + if (!responseHeaders.empty()) { + QNetworkReplyWasmImplPrivate *reply = + reinterpret_cast<QNetworkReplyWasmImplPrivate*>(xhr["data-handler"].as<quintptr>()); + Q_ASSERT(reply); + + reply->headersReceived(QString::fromStdString(responseHeaders)); + } + } +} + +static void q_readBinary(val event) +{ + val fileReader = event["target"]; + + QNetworkReplyWasmImplPrivate *reply = + reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fileReader["data-handler"].as<quintptr>()); + Q_ASSERT(reply); + + // Set up source typed array + val result = fileReader["result"]; // ArrayBuffer + val Uint8Array = val::global("Uint8Array"); + val sourceTypedArray = Uint8Array.new_(result); + + // Allocate and set up destination typed array + const quintptr size = result["byteLength"].as<quintptr>(); + QByteArray buffer(size, Qt::Uninitialized); + + val destinationTypedArray = Uint8Array.new_(val::module_property("HEAPU8")["buffer"], + reinterpret_cast<quintptr>(buffer.data()), size); + destinationTypedArray.call<void>("set", sourceTypedArray); + reply->dataReceived(buffer, buffer.size()); +} + + +EMSCRIPTEN_BINDINGS(network_module) { + function("QNetworkReplyWasmImplPrivate_requestErrorCallback", q_requestErrorCallback); + function("QNetworkReplyWasmImplPrivate_progressCallback", q_progressCallback); + function("QNetworkReplyWasmImplPrivate_loadCallback", q_loadCallback); + function("QNetworkReplyWasmImplPrivate_responseHeadersCallback", q_responseHeadersCallback); + function("QNetworkReplyWasmImplPrivate_readBinary", q_readBinary); +} + QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate() : QNetworkReplyPrivate() , managerPrivate(0) @@ -172,226 +297,80 @@ void QNetworkReplyWasmImplPrivate::setup(QNetworkAccessManager::Operation op, co doSendRequest(); } -void QNetworkReplyWasmImplPrivate::onLoadCallback(void *data, int statusCode, int statusReason, int readyState, int buffer, int bufferSize) -{ - QNetworkReplyWasmImplPrivate *handler = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(data); - - const QString reasonStr = QString::fromUtf8(reinterpret_cast<char *>(statusReason)); - - switch (readyState) { - case 0://unsent - break; - case 1://opened - break; - case 2://headers received - break; - case 3://loading - break; - case 4: {//done - handler->q_func()->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode); - if (!reasonStr.isEmpty()) - handler->q_func()->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonStr); - - if (statusCode >= 400) { - if (!reasonStr.isEmpty()) - handler->emitReplyError(handler->statusCodeFromHttp(statusCode, handler->request.url()), reasonStr); - } else { - handler->dataReceived(reinterpret_cast<char *>(buffer), bufferSize); - } - } - break; - }; - } - -void QNetworkReplyWasmImplPrivate::onProgressCallback(void* data, int bytesWritten, int total, uint timestamp) -{ - Q_UNUSED(timestamp); - - QNetworkReplyWasmImplPrivate *handler = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(data); - handler->emitDataReadProgress(bytesWritten, total); -} - -void QNetworkReplyWasmImplPrivate::onRequestErrorCallback(void* data, int statusCode, int statusReason) +void QNetworkReplyWasmImplPrivate::setReplyAttributes(quintptr data, int statusCode, const QString &statusReason) { - QString reasonStr = QString::fromUtf8(reinterpret_cast<char *>(statusReason)); - QNetworkReplyWasmImplPrivate *handler = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(data); + Q_ASSERT(handler); handler->q_func()->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode); - if (!reasonStr.isEmpty()) - handler->q_func()->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonStr); - - if (statusCode >= 400) { - if (!reasonStr.isEmpty()) - handler->emitReplyError(handler->statusCodeFromHttp(statusCode, handler->request.url()), reasonStr); - } -} - -void QNetworkReplyWasmImplPrivate::onResponseHeadersCallback(void* data, int headers) -{ - QNetworkReplyWasmImplPrivate *handler = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(data); - handler->headersReceived(reinterpret_cast<char *>(headers)); + if (!statusReason.isEmpty()) + handler->q_func()->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, statusReason); } void QNetworkReplyWasmImplPrivate::doSendRequest() { Q_Q(QNetworkReplyWasmImpl); totalDownloadSize = 0; - jsRequest(QString::fromUtf8(q->methodName()), // GET POST - request.url().toString(), - (void *)&onLoadCallback, - (void *)&onProgressCallback, - (void *)&onRequestErrorCallback, - (void *)&onResponseHeadersCallback); -} - -/* const QString &body, const QList<QPair<QByteArray, QByteArray> > &headers ,*/ -void QNetworkReplyWasmImplPrivate::jsRequest(const QString &verb, const QString &url, - void *loadCallback, void *progressCallback, - void *errorCallback, void *onResponseHeadersCallback) -{ - QString extraDataString; - - QByteArray extraData; - if (outgoingData) - extraData = outgoingData->readAll(); - if (extraData.size() > 0) - extraDataString.fromUtf8(extraData); + val xhr = val::global("XMLHttpRequest").new_(); + std::string verb = q->methodName().toStdString(); - if (extraDataString.size() >= 0 && verb == QStringLiteral("POST") && extraDataString.startsWith(QStringLiteral("?"))) - extraDataString.remove(QStringLiteral("?")); + QUrl url; + QString extraDataString; - // Probably a good idea to save any shared pointers as members in C++ - // so the objects they point to survive as long as you need them + if (request.url().hasQuery()) { //strip query from url + extraDataString = request.url().query(QUrl::FullyEncoded); + QString urlStr = request.url().toString(); + url.setUrl(urlStr.left(urlStr.indexOf("?"))); + } else { + url = request.url(); + } + xhr.call<void>("open", verb, url.toString().toStdString()); - QStringList headersList; - for (auto header : request.rawHeaderList()) - headersList << QString::fromUtf8(header + ":" + request.rawHeader(header)); + xhr.set("onerror", val::module_property("QNetworkReplyWasmImplPrivate_requestErrorCallback")); + xhr.set("onload", val::module_property("QNetworkReplyWasmImplPrivate_loadCallback")); + xhr.set("onprogress", val::module_property("QNetworkReplyWasmImplPrivate_progressCallback")); + xhr.set("onreadystatechange", val::module_property("QNetworkReplyWasmImplPrivate_responseHeadersCallback")); - EM_ASM_ARGS({ - var verb = Pointer_stringify($0); - var url = Pointer_stringify($1); - var onLoadCallbackPointer = $2; - var onProgressCallbackPointer = $3; - var onErrorCallbackPointer = $4; - var onHeadersCallback = $5; - var handler = $8; + xhr.set("data-handler", val(quintptr(reinterpret_cast<void *>(this)))); - var dataToSend; - var extraRequestData = Pointer_stringify($6); // request parameters - var headersData = Pointer_stringify($7); + QByteArray contentType = request.rawHeader("Content-Type"); - var xhr; - xhr = new XMLHttpRequest(); - xhr.responseType = 'arraybuffer'; + // handle extra data + val dataToSend = val::null(); + QByteArray extraData; - xhr.open(verb, url, true); //async + if (outgoingData) // data from post request + extraData = outgoingData->readAll(); - function handleError(xhrStatusCode, xhrStatusText) { - var errorPtr = allocate(intArrayFromString(xhrStatusText), 'i8', ALLOC_NORMAL); - Runtime.dynCall('viii', onErrorCallbackPointer, [handler, xhrStatusCode, errorPtr]); - _free(errorPtr); + if (contentType.contains("text") || + contentType.contains("json") || + contentType.contains("form")) { + if (extraData.size() > 0) + extraDataString.fromUtf8(extraData); + } + if (contentType.contains("json")) { + if (!extraDataString.isEmpty()) { + xhr.set("responseType", val("json")); + dataToSend = val(extraDataString.toStdString()); } + } + if (contentType.contains("form")) { //construct form data + if (!extraDataString.isEmpty()) { + val formData = val::global("FormData").new_(); + QStringList formList = extraDataString.split('&'); - if (headersData) { - var headers = headersData.split("&"); - for (var i = 0; i < headers.length; i++) { - var header = headers[i].split(":")[0]; - var value = headers[i].split(":")[1]; - - if (verb === 'POST' && value.toLowerCase().includes('json')) { - if (extraRequestData) { - xhr.responseType = 'json'; - dataToSend = extraRequestData; - } - } - if (verb === 'POST' && value.toLowerCase().includes('form')) { - if (extraRequestData) { - var formData = new FormData(); - var extra = extraRequestData.split("&"); - for (var i = 0; i < extra.length; i++) { - formData.append(extra[i].split("=")[0],extra[i].split("=")[1]); - } - dataToSend = formData; - } - } - xhr.setRequestHeader(header, value); + for (auto formEntry : formList) { + formData.call<void>("append", formEntry.split('=')[0].toStdString(), formEntry.split('=')[1].toStdString()); } + dataToSend = formData; } - - xhr.onprogress = function(e) { - switch (xhr.status) { - case 200: - case 206: - case 300: - case 301: - case 302: { - var date = xhr.getResponseHeader('Last-Modified'); - date = ((date != null) ? new Date(date).getTime() / 1000 : 0); - Runtime.dynCall('viiii', onProgressCallbackPointer, [handler, e.loaded, e.total, date]); - } - break; - } - }; - - xhr.onreadystatechange = function() { - if (this.readyState == this.HEADERS_RECEIVED) { - var responseStr = this.getAllResponseHeaders(); - if (responseStr.length > 0) { - var ptr = allocate(intArrayFromString(responseStr), 'i8', ALLOC_NORMAL); - Runtime.dynCall('vii', onHeadersCallback, [handler, ptr]); - _free(ptr); - } - } - }; - - xhr.onload = function(e) { - if (xhr.status >= 300) { //error - handleError(xhr.status, xhr.statusText); - } else { - if (this.status == 200 || this.status == 203) { - var datalength; - var byteArray = 0; - var buffer; - if (this.responseType.length === 0 || this.responseType === 'document') { - byteArray = new Uint8Array(this.responseText); - } else if (this.responseType === 'json') { - var jsonResponse = JSON.stringify(this.response); - buffer = allocate(intArrayFromString(jsonResponse), 'i8', ALLOC_NORMAL); - datalength = jsonResponse.length; - } else if (this.responseType === 'arraybuffer') { - byteArray = new Uint8Array(xhr.response); - } - if (byteArray != 0 ) { - datalength = byteArray.length; - buffer = _malloc(datalength); - HEAPU8.set(byteArray, buffer); - } - var reasonPtr = allocate(intArrayFromString(this.statusText), 'i8', ALLOC_NORMAL); - Runtime.dynCall('viiiiii', onLoadCallbackPointer, [handler, this.status, reasonPtr, this.readyState, buffer, datalength]); - _free(buffer); - _free(reasonPtr); - } - } - }; - - xhr.onerror = function(e) { - handleError(xhr.status, xhr.statusText); - }; - //TODO other operations, handle user/pass, handle binary data, data streaming - xhr.send(dataToSend); - - }, verb.toLatin1().data(), - url.toLatin1().data(), - loadCallback, - progressCallback, - errorCallback, - onResponseHeadersCallback, - extraDataString.size() > 0 ? extraDataString.toLatin1().data() : extraData.data(), - headersList.join(QStringLiteral("&")).toLatin1().data(), - this - ); + } + // set request headers + for (auto header : request.rawHeaderList()) { + xhr.call<void>("setRequestHeader", header.toStdString(), request.rawHeader(header).toStdString()); + } + xhr.call<void>("send", dataToSend); } void QNetworkReplyWasmImplPrivate::emitReplyError(QNetworkReply::NetworkError errorCode, const QString &errorString) @@ -414,10 +393,10 @@ void QNetworkReplyWasmImplPrivate::emitDataReadProgress(qint64 bytesReceived, qi percentFinished = (bytesReceived / bytesTotal) * 100; - emit q->downloadProgress(bytesReceived, totalDownloadSize); + emit q->downloadProgress(bytesReceived, bytesTotal); } -void QNetworkReplyWasmImplPrivate::dataReceived(char *buffer, int bufferSize) +void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer, int bufferSize) { Q_Q(QNetworkReplyWasmImpl); @@ -481,11 +460,10 @@ static int parseHeaderName(const QByteArray &headerName) } -void QNetworkReplyWasmImplPrivate::headersReceived(char *buffer) +void QNetworkReplyWasmImplPrivate::headersReceived(const QString &bufferString) { Q_Q(QNetworkReplyWasmImpl); - QString bufferString = QString::fromUtf8(buffer); if (!bufferString.isEmpty()) { QStringList headers = bufferString.split(QString::fromUtf8("\r\n"), QString::SkipEmptyParts); diff --git a/src/network/access/qnetworkreplywasmimpl_p.h b/src/network/access/qnetworkreplywasmimpl_p.h index a707390503..69c90de41a 100644 --- a/src/network/access/qnetworkreplywasmimpl_p.h +++ b/src/network/access/qnetworkreplywasmimpl_p.h @@ -95,7 +95,6 @@ public: private: QByteArray methodName() const; - }; class QNetworkReplyWasmImplPrivate: public QNetworkReplyPrivate @@ -106,19 +105,12 @@ public: QNetworkAccessManagerPrivate *managerPrivate; void doSendRequest(); - - void jsRequest(const QString &verb, const QString &url, void *, void *, void *, void *); - - static void onLoadCallback(void *data, int statusCode, int statusReason, int readyState, int textBuffer, int size); - static void onProgressCallback(void *data, int done, int bytesTotal, uint timestamp); - static void onRequestErrorCallback(void *data, int statusCode, int statusReason); - static void onStateChangedCallback(int status); - static void onResponseHeadersCallback(void *data, int headers); + static void setReplyAttributes(quintptr data, int statusCode, const QString &statusReason); void emitReplyError(QNetworkReply::NetworkError errorCode, const QString &); void emitDataReadProgress(qint64 done, qint64 total); - void dataReceived(char *buffer, int bufferSize); - void headersReceived(char *buffer); + void dataReceived(const QByteArray &buffer, int bufferSize); + void headersReceived(const QString &bufferString); void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData); @@ -148,6 +140,4 @@ public: QT_END_NAMESPACE -//Q_DECLARE_METATYPE(QNetworkRequest::KnownHeaders) - #endif // QNETWORKREPLYWASMIMPL_H diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp b/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp index 06f0aa6747..dc4785071f 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp @@ -48,26 +48,78 @@ QT_BEGIN_NAMESPACE +struct GUserEventSource +{ + GSource source; + QPAEventDispatcherGlib *q; +}; + +static gboolean userEventSourcePrepare(GSource *source, gint *timeout) +{ + Q_UNUSED(timeout) + GUserEventSource *userEventSource = reinterpret_cast<GUserEventSource *>(source); + QPAEventDispatcherGlib *dispatcher = userEventSource->q; + if (dispatcher->m_flags & QEventLoop::ExcludeUserInputEvents) + return QWindowSystemInterface::nonUserInputEventsQueued(); + else + return QWindowSystemInterface::windowSystemEventsQueued() > 0; +} + +static gboolean userEventSourceCheck(GSource *source) +{ + return userEventSourcePrepare(source, 0); +} + +static gboolean userEventSourceDispatch(GSource *source, GSourceFunc, gpointer) +{ + GUserEventSource *userEventSource = reinterpret_cast<GUserEventSource *>(source); + QPAEventDispatcherGlib *dispatcher = userEventSource->q; + QWindowSystemInterface::sendWindowSystemEvents(dispatcher->m_flags); + return true; +} + +static GSourceFuncs userEventSourceFuncs = { + userEventSourcePrepare, + userEventSourceCheck, + userEventSourceDispatch, + NULL, + NULL, + NULL +}; + QPAEventDispatcherGlibPrivate::QPAEventDispatcherGlibPrivate(GMainContext *context) : QEventDispatcherGlibPrivate(context) { + Q_Q(QPAEventDispatcherGlib); + userEventSource = reinterpret_cast<GUserEventSource *>(g_source_new(&userEventSourceFuncs, + sizeof(GUserEventSource))); + userEventSource->q = q; + g_source_set_can_recurse(&userEventSource->source, true); + g_source_attach(&userEventSource->source, mainContext); } + QPAEventDispatcherGlib::QPAEventDispatcherGlib(QObject *parent) : QEventDispatcherGlib(*new QPAEventDispatcherGlibPrivate, parent) , m_flags(QEventLoop::AllEvents) { + Q_D(QPAEventDispatcherGlib); + d->userEventSource->q = this; } QPAEventDispatcherGlib::~QPAEventDispatcherGlib() { + Q_D(QPAEventDispatcherGlib); + + g_source_destroy(&d->userEventSource->source); + g_source_unref(&d->userEventSource->source); + d->userEventSource = 0; } bool QPAEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags) { m_flags = flags; - const bool didSendEvents = QEventDispatcherGlib::processEvents(m_flags); - return QWindowSystemInterface::sendWindowSystemEvents(m_flags) || didSendEvents; + return QEventDispatcherGlib::processEvents(m_flags); } QT_END_NAMESPACE diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h b/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h index 5930dc68e7..085a1c52f3 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h @@ -71,11 +71,14 @@ public: QEventLoop::ProcessEventsFlags m_flags; }; +struct GUserEventSource; + class QPAEventDispatcherGlibPrivate : public QEventDispatcherGlibPrivate { Q_DECLARE_PUBLIC(QPAEventDispatcherGlib) public: QPAEventDispatcherGlibPrivate(GMainContext *context = 0); + GUserEventSource *userEventSource; }; diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json index b618d8567a..3cfa7e3856 100644 --- a/src/plugins/platforms/windows/openglblacklists/default.json +++ b/src/plugins/platforms/windows/openglblacklists/default.json @@ -144,9 +144,8 @@ }, { "id": 12, - "description": "Intel HD Graphics 620 crash in conjunction with shader caches (QTBUG-64697)", + "description": "Intel HD Graphics crash in conjunction with shader caches (QTBUG-64697) - disable for all Intel GPUs", "vendor_id": "0x8086", - "device_id": [ "0x5916" ], "os": { "type": "win" }, diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp index b3bf52f09b..c23d48b2dd 100644 --- a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp +++ b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp @@ -118,11 +118,14 @@ void QWinRTBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo if (d->size.isEmpty()) return; + const QRect bounds = region.boundingRect() & d->paintDevice.rect(); + if (bounds.isEmpty()) + return; + const bool ok = d->context->makeCurrent(window); if (!ok) qWarning("unable to flush"); - const QRect bounds = region.boundingRect(); glBindTexture(GL_TEXTURE_2D, d->fbo->texture()); // TODO: when ANGLE GLES3 support is finished, use the glPixelStorei functions to minimize upload glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.y(), d->size.width(), bounds.height(), diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 6dda6487c8..4e24c970b4 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -90,25 +90,6 @@ #include <xcb/render.h> #endif -#if defined(Q_CC_GNU) && defined(Q_OF_ELF) -static xcb_generic_event_t *local_xcb_poll_for_queued_event(xcb_connection_t *c) - __attribute__((weakref("xcb_poll_for_queued_event"))); - -static inline void checkXcbPollForQueuedEvent() -{ } -#else -#include <dlfcn.h> -typedef xcb_generic_event_t * (*XcbPollForQueuedEventFunctionPointer)(xcb_connection_t *c); -static XcbPollForQueuedEventFunctionPointer local_xcb_poll_for_queued_event; - -static inline void checkXcbPollForQueuedEvent() -{ -#ifdef RTLD_DEFAULT - local_xcb_poll_for_queued_event = (XcbPollForQueuedEventFunctionPointer)dlsym(RTLD_DEFAULT, "xcb_poll_for_queued_event"); -#endif -} -#endif - QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaXInput, "qt.qpa.input") @@ -1365,39 +1346,19 @@ bool QXcbConnection::peekEventQueue(PeekerCallback peeker, void *peekerData, QXcbEventReader::QXcbEventReader(QXcbConnection *connection) : m_connection(connection) { - checkXcbPollForQueuedEvent(); } void QXcbEventReader::start() { - if (local_xcb_poll_for_queued_event) { - connect(this, SIGNAL(eventPending()), m_connection, SLOT(processXcbEvents()), Qt::QueuedConnection); - connect(this, SIGNAL(finished()), m_connection, SLOT(processXcbEvents())); - QThread::start(); - } else { - // Must be done after we have an event-dispatcher. By posting a method invocation - // we are sure that by the time the method is called we have an event-dispatcher. - QMetaObject::invokeMethod(this, "registerForEvents", Qt::QueuedConnection); - } -} - -void QXcbEventReader::registerForEvents() -{ - QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection->xcb_connection()), QSocketNotifier::Read, this); - connect(notifier, SIGNAL(activated(int)), m_connection, SLOT(processXcbEvents())); - - QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; - connect(dispatcher, SIGNAL(aboutToBlock()), m_connection, SLOT(processXcbEvents())); - connect(dispatcher, SIGNAL(awake()), m_connection, SLOT(processXcbEvents())); + connect(this, &QXcbEventReader::eventPending, m_connection, &QXcbConnection::processXcbEvents, Qt::QueuedConnection); + connect(this, &QXcbEventReader::finished, m_connection, &QXcbConnection::processXcbEvents); + QThread::start(); } void QXcbEventReader::registerEventDispatcher(QAbstractEventDispatcher *dispatcher) { - // flush the xcb connection before the EventDispatcher is going to block - // In the non-threaded case processXcbEvents is called before going to block, - // which flushes the connection. - if (local_xcb_poll_for_queued_event) - connect(dispatcher, SIGNAL(aboutToBlock()), m_connection, SLOT(flush())); + // Flush the xcb connection before the event dispatcher is going to block. + connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, m_connection, &QXcbConnection::flush); } void QXcbEventReader::run() @@ -1406,7 +1367,7 @@ void QXcbEventReader::run() while (m_connection && (event = xcb_wait_for_event(m_connection->xcb_connection()))) { m_mutex.lock(); addEvent(event); - while (m_connection && (event = local_xcb_poll_for_queued_event(m_connection->xcb_connection()))) + while (m_connection && (event = xcb_poll_for_queued_event(m_connection->xcb_connection()))) addEvent(event); m_mutex.unlock(); emit eventPending(); @@ -1430,10 +1391,6 @@ void QXcbEventReader::addEvent(xcb_generic_event_t *event) QXcbEventArray *QXcbEventReader::lock() { m_mutex.lock(); - if (!local_xcb_poll_for_queued_event) { - while (xcb_generic_event_t *event = xcb_poll_for_event(m_connection->xcb_connection())) - m_events << event; - } return &m_events; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 1e28ef8fac..db45031cf4 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -326,9 +326,6 @@ public: signals: void eventPending(); -private slots: - void registerForEvents(); - private: void addEvent(xcb_generic_event_t *event); @@ -493,8 +490,6 @@ public: bool hasShmFd() const { return has_shm_fd; } bool hasXSync() const { return has_sync_extension; } - bool threadedEventHandling() const { return m_reader->isRunning(); } - xcb_timestamp_t getTimestamp(); xcb_window_t getSelectionOwner(xcb_atom_t atom) const; xcb_window_t getQtSelectionOwner(); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 9fc1189181..db8dc09025 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -308,8 +308,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const { const auto *connection = qAsConst(m_connections).first(); if (const auto *integration = connection->glIntegration()) - return cap != ThreadedOpenGL - || (connection->threadedEventHandling() && integration->supportsThreadedOpenGL()); + return cap != ThreadedOpenGL || integration->supportsThreadedOpenGL(); return false; } diff --git a/tests/auto/network/ssl/ssl.pro b/tests/auto/network/ssl/ssl.pro index a2d9159579..e89443ef4e 100644 --- a/tests/auto/network/ssl/ssl.pro +++ b/tests/auto/network/ssl/ssl.pro @@ -16,7 +16,7 @@ qtConfig(ssl) { qsslsocket_onDemandCertificates_member \ qsslsocket_onDemandCertificates_static - qtConfig(openssl) { + qtConfig(dtls) { SUBDIRS += \ qdtlscookie \ qdtls |