From d941ebc1505cc45c7d6f8e1b2abdd2e2d9c3afae Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 4 Dec 2018 13:33:10 +0100 Subject: [PATCH 01/13] qmake: fix QMAKE_DEFAULT_LIBDIRS detection for android on windows clearly, nobody told clang that on windows you're supposed to use semicolons instead of colons to separate elements of a path list ... Fixes: QTBUG-72268 Change-Id: Ia7adc8de3bca586d4c15b069cb04e4cb647ae823 Reviewed-by: Liang Qi Reviewed-by: Joerg Bornemann --- mkspecs/features/toolchain.prf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mkspecs/features/toolchain.prf b/mkspecs/features/toolchain.prf index 6039c52bd0..55295f271f 100644 --- a/mkspecs/features/toolchain.prf +++ b/mkspecs/features/toolchain.prf @@ -134,6 +134,8 @@ isEmpty($${target_prefix}.INCDIRS) { for (line, output) { contains(line, "^libraries: .*") { line ~= s,^libraries: ,, + # clang (7.x) on Windows uses the wrong path list separator ... + equals(QMAKE_HOST.os, Windows): line ~= s,:(?![/\\\\]),;, paths = $$split(line, $$QMAKE_DIRLIST_SEP) for (path, paths): \ QMAKE_DEFAULT_LIBDIRS += $$clean_path($$replace(path, ^=, $$[SYSROOT])) From 33276e1cf14095c681ef87f1b44809b5ee1e771f Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 17 Apr 2018 19:17:25 +0200 Subject: [PATCH 02/13] add support for transitive deps to QMAKE_USE we already knew the dependencies (as they are declared in the json files), but failed to export them in any way, which made linking against statically built external deps which have deps in turn fail (unless the project happened to pull in the dep anyway, as is the case with qtcore + zlib). the previous assumption was that the USE-able library objects would be self-contained, but that is conceptually unclean. instead, properly export the raw dependencies and resolve them only in qmake_use.prf. note that pkg-config produces self-contained output, so we need to actively subtract the dependencies we know. Change-Id: I4b41a7efc05bbd309a6d66275d7557a80efd5af4 Reviewed-by: Joerg Bornemann Reviewed-by: Oswald Buddenhagen --- mkspecs/features/qmake_use.prf | 32 +++++++++------ mkspecs/features/qt_configure.prf | 62 ++++++++++++++++++++++++++--- mkspecs/features/qt_helper_lib.prf | 13 ++++++ mkspecs/features/qt_module_pris.prf | 1 + 4 files changed, 90 insertions(+), 18 deletions(-) diff --git a/mkspecs/features/qmake_use.prf b/mkspecs/features/qmake_use.prf index dba45de92a..8159e471a2 100644 --- a/mkspecs/features/qmake_use.prf +++ b/mkspecs/features/qmake_use.prf @@ -1,23 +1,31 @@ suffix = for(ever) { - QMAKE_USE$${suffix} = $$unique(QMAKE_USE$${suffix}) + CC_USES = + LD_USES = for (use, QMAKE_USE$${suffix}) { use = $$split(use, /) name = $$take_first(use) nu = $$upper($$name) + !contains(use, linkonly): CC_USES += $$nu + !contains(use, nolink): LD_USES += $$nu + } + CC_USES = $$resolve_depends(CC_USES, QMAKE_DEPENDS_, _CC) + for (nu, CC_USES) { !defined(QMAKE_LIBS_$$nu, var): \ - error("Library '$$name' is not defined.") + error("Library '$$lower($$nu)' is not defined.") - !contains(use, nolink) { - debug: \ - LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_DEBUG) $$eval(QMAKE_LIBS_$$nu) - else: \ - LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_RELEASE) $$eval(QMAKE_LIBS_$$nu) - } - !contains(use, linkonly) { - DEFINES += $$eval(QMAKE_DEFINES_$${nu}) - INCLUDEPATH += $$eval(QMAKE_INCDIR_$${nu}) - } + DEFINES += $$eval(QMAKE_DEFINES_$${nu}) + INCLUDEPATH += $$eval(QMAKE_INCDIR_$${nu}) + } + LD_USES = $$resolve_depends(LD_USES, QMAKE_DEPENDS_, _LD) + for (nu, LD_USES) { + !defined(QMAKE_LIBS_$$nu, var): \ + error("Library '$$lower($$nu)' is not defined.") + + debug: \ + LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_DEBUG) $$eval(QMAKE_LIBS_$$nu) + else: \ + LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_RELEASE) $$eval(QMAKE_LIBS_$$nu) } !isEmpty(suffix): break() suffix = "_PRIVATE" diff --git a/mkspecs/features/qt_configure.prf b/mkspecs/features/qt_configure.prf index d75365cd0a..d8f5af5404 100644 --- a/mkspecs/features/qt_configure.prf +++ b/mkspecs/features/qt_configure.prf @@ -743,6 +743,21 @@ defineTest(qtConfLibrary_pkgConfig) { !qtConfResolvePathIncs($${1}.includedir, $$includes): \ return(false) $${1}.defines = $$defines + + # now remove the content of the transitive deps we know about. + largs = $$qtConfAllLibraryArgs($$eval($${2}.dependencies)) + for (la, largs): \ + eval("$$la") + USES = $$eval($$list($$upper($$QMAKE_USE))) + # _CC == _LD for configure's library sources, so pick first arbitrarily. + DEPS = $$resolve_depends(USES, QMAKE_DEPENDS_, _CC) + for (DEP, DEPS) { + $${1}.libs -= $$eval(QMAKE_LIBS_$${DEP}) + $${1}.includedir -= $$eval(QMAKE_INCDIR_$${DEP}) + $${1}.defines -= $$eval(QMAKE_DEFINES_$${DEP}) + } + export($${1}.libs) + export($${1}.includedir) export($${1}.defines) return(true) @@ -776,20 +791,36 @@ defineReplace(qtConfLibraryArgs) { defines = $$eval($${1}.defines) !isEmpty(defines): \ qmake_args += "QMAKE_DEFINES_$${NAME} = $$val_escape(defines)" + depends = $$eval($${2}.dependencies) + !isEmpty(depends) { + dep_uses = + for (use, depends): \ + dep_uses += $$section(use, :, 1, 1) + qmake_args += \ + "QMAKE_DEPENDS_$${NAME}_CC = $$upper($$dep_uses)" \ + "QMAKE_DEPENDS_$${NAME}_LD = $$upper($$dep_uses)" + } return($$qmake_args) } defineReplace(qtConfAllLibraryArgs) { isEmpty(1): return() dep_uses = + for (use, 1): \ + dep_uses += $$section(use, :, 1, 1) dep_args = - for (use, 1) { + seen = + for(ever) { + isEmpty(1): break() + use = $$take_last(1) + contains(seen, $$use): next() + seen += $$use use_cfg = $$section(use, :, 0, 0) - use_lib = $$section(use, :, 1, 1) - dep_uses += $$use_lib !isEmpty(use_cfg) { + use_lib = $$section(use, :, 1, 1) lpfx = $${use_cfg}.libraries.$$use_lib - dep_args += $$qtConfLibraryArgs($${lpfx}.sources.$$eval($${lpfx}.source)) + dep_args += $$qtConfLibraryArgs($${lpfx}.sources.$$eval($${lpfx}.source), $$lpfx) + 1 += $$eval($${lpfx}.dependencies) } } return("QMAKE_USE += $$dep_uses" $$dep_args) @@ -818,6 +849,24 @@ defineTest(qtConfExportLibrary) { !isEmpty(defines): qtConfOutputVar(assign, $$output, QMAKE_DEFINES_$$NAME, $$defines) includes = $$eval($${spfx}.includedir) !isEmpty(includes): qtConfOutputVar(assign, $$output, QMAKE_INCDIR_$$NAME, $$includes) + uses = $$eval($${lpfx}.dependencies) + !isEmpty(uses) { + # FIXME: ideally, we would export transitive deps only for static + # libs, to not extend the link interface unduly. however, the system + # does currently not differentiate between public and private deps. + depends = + for (use, uses) { + use_cfg = $$section(use, :, 0, 0) + use_lib = $$section(use, :, 1, 1) + !isEmpty(use_cfg): \ + depends += $$upper($$eval($${use_cfg}.libraries.$${use_lib}.export)) + else: \ + depends += $$upper($$use_lib) + } + # we use suffixes instead of infixes, because $$resolve_depends() demands it. + qtConfOutputVar(assign, $$output, QMAKE_DEPENDS_$${NAME}_CC, $$depends) + qtConfOutputVar(assign, $$output, QMAKE_DEPENDS_$${NAME}_LD, $$depends) + } !isEmpty($${currentConfig}.module): \ qtConfExtendVar($$output, "QT.$${currentModule}_private.libraries", $$name) } @@ -843,7 +892,8 @@ defineTest(qtConfHandleLibrary) { export($${lpfx}.result) return() } - resolved_uses = $$eval($${lpfx}.resolved_uses) + $${lpfx}.dependencies = $$eval($${lpfx}.resolved_uses) + export($${lpfx}.dependencies) qtConfLoadResult($${lpfx}, $$1, "library") { $$eval($${lpfx}.result): \ @@ -881,7 +931,7 @@ defineTest(qtConfHandleLibrary) { # if the library defines a test, use it to verify the source. !isEmpty($${lpfx}.test)|!isEmpty($${lpfx}.test._KEYS_) { - $${lpfx}.resolved_uses = $$currentConfig:$$1 $$resolved_uses + $${lpfx}.resolved_uses = $$currentConfig:$$1 $${lpfx}.host = $$eval($${spfx}.host) !qtConfTest_compile($$lpfx) { qtLog(" => source failed verification.") diff --git a/mkspecs/features/qt_helper_lib.prf b/mkspecs/features/qt_helper_lib.prf index 1a8446acb4..05d3b941bd 100644 --- a/mkspecs/features/qt_helper_lib.prf +++ b/mkspecs/features/qt_helper_lib.prf @@ -41,7 +41,20 @@ THE_TARGET = $$qt5LibraryTarget($$TARGET) prefix = $$QMAKE_PREFIX_SHLIB suffix = $$QMAKE_EXTENSION_SHLIB } + CC_USES = + LD_USES = + for (use, QMAKE_USE) { + use = $$split(use, /) + name = $$take_first(use) + nu = $$upper($$name) + !contains(use, linkonly): CC_USES += $$nu + !contains(use, nolink): LD_USES += $$nu + } + CC_USES = $$unique(CC_USES) + LD_USES = $$unique(LD_USES) MODULE_PRI_CONT = \ + "QMAKE_DEPENDS_$${ucmodule}_CC =$$join(CC_USES, " ", " ")" \ + "QMAKE_DEPENDS_$${ucmodule}_LD =$$join(LD_USES, " ", " ")" \ "QMAKE_INCDIR_$${ucmodule} = $$val_escape(MODULE_INCLUDEPATH)" \ "QMAKE_DEFINES_$${ucmodule} = $$val_escape(MODULE_DEFINES)" debug_and_release { diff --git a/mkspecs/features/qt_module_pris.prf b/mkspecs/features/qt_module_pris.prf index 163f52f23f..e0556ce960 100644 --- a/mkspecs/features/qt_module_pris.prf +++ b/mkspecs/features/qt_module_pris.prf @@ -56,6 +56,7 @@ defineReplace(qtExportLibsForModule) { for (lib, QT.$${1}.libraries) { NAME = $$upper($$lib) vars = \ + QMAKE_DEPENDS_$${NAME}_CC QMAKE_DEPENDS_$${NAME}_LD \ QMAKE_LIBS_$$NAME QMAKE_LIBS_$${NAME}_DEBUG QMAKE_LIBS_$${NAME}_RELEASE \ QMAKE_DEFINES_$$NAME QMAKE_INCDIR_$$NAME for (var, vars) { From fc2c4edcbda8be88900201383b5113e234b09d71 Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Wed, 10 May 2017 12:56:51 +0200 Subject: [PATCH 03/13] configure: fix linking with statically linked freetype freetype depends on zlib. using statically linked freetype as system library lacks the usage requirement to link with zlib. so we need to add this manually. Task-number: QTBUG-63115 Change-Id: Iaf0f3027bd9d1386fcc1ecfbfbe07ab09b2d0bb9 Reviewed-by: Oswald Buddenhagen Reviewed-by: Joerg Bornemann --- src/gui/configure.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/configure.json b/src/gui/configure.json index 6a2f1fe434..0d4f167d47 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -164,6 +164,9 @@ { "type": "pkgConfig", "args": "freetype2" }, { "type": "freetype", "libs": "-lfreetype", "condition": "!config.wasm" }, { "type": "freetype", "libs": "-s USE_FREETYPE=1", "condition": "config.wasm" } + ], + "use": [ + { "lib": "zlib", "condition": "features.system-zlib" } ] }, "fontconfig": { From b6737b7ecd54484eda471b905d25cc1a17c4e072 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 19 Oct 2018 19:30:33 +0200 Subject: [PATCH 04/13] wasm: fix freetype library source Change-Id: Ib99c4c178808c7325e55e85a1548542ae3c57524 Reviewed-by: Lorn Potter --- src/gui/configure.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/configure.json b/src/gui/configure.json index 0d4f167d47..3d0f75254a 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -163,7 +163,7 @@ "sources": [ { "type": "pkgConfig", "args": "freetype2" }, { "type": "freetype", "libs": "-lfreetype", "condition": "!config.wasm" }, - { "type": "freetype", "libs": "-s USE_FREETYPE=1", "condition": "config.wasm" } + { "libs": "-s USE_FREETYPE=1", "condition": "config.wasm" } ], "use": [ { "lib": "zlib", "condition": "features.system-zlib" } From 118b456c6b6bb81b879b4c8940414c0c10a57d4a Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 1 Dec 2017 19:25:43 +0100 Subject: [PATCH 05/13] configure: convert xlib to a proper library definition Change-Id: I1623aee9e8632e4bfd466e09e275cc23f94c6dab Reviewed-by: Gatis Paeglis --- config.tests/x11/xrender/xrender.pro | 1 - src/gui/configure.json | 30 ++++++++++--------- .../eglconvenience/eglconvenience.pro | 2 +- .../glxconvenience/glxconvenience.pro | 2 +- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/config.tests/x11/xrender/xrender.pro b/config.tests/x11/xrender/xrender.pro index ab5c5efa77..6244ae6b47 100644 --- a/config.tests/x11/xrender/xrender.pro +++ b/config.tests/x11/xrender/xrender.pro @@ -1,3 +1,2 @@ SOURCES = xrender.cpp -CONFIG += x11 CONFIG -= qt diff --git a/src/gui/configure.json b/src/gui/configure.json index 3d0f75254a..123ef208a2 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -454,6 +454,19 @@ { "type": "pkgConfig", "args": "wayland-server" } ] }, + "xlib": { + "label": "XLib", + "test": { + "include": "X11/Xlib.h", + "main": [ + "Display *d = XOpenDisplay(NULL);", + "XCloseDisplay(d);" + ] + }, + "sources": [ + { "type": "makeSpec", "spec": "X11" } + ] + }, "x11sm": { "label": "X11 session management", "sources": [ @@ -626,7 +639,8 @@ "test": "x11/xrender", "sources": [ "-lXrender" - ] + ], + "use": "xlib" } }, @@ -913,18 +927,6 @@ "pkg-config-variable": "prefix", "value": "/usr", "log": "value" - }, - "xlib": { - "label": "XLib", - "type": "compile", - "test": { - "include": "X11/Xlib.h", - "main": [ - "Display *d = XOpenDisplay(NULL);", - "XCloseDisplay(d);" - ], - "qmake": "CONFIG += x11" - } } }, @@ -1374,7 +1376,7 @@ "xlib": { "label": "XLib", "autoDetect": "!config.darwin || features.xcb", - "condition": "tests.xlib", + "condition": "libs.xlib", "output": [ "privateFeature" ] }, "texthtmlparser": { diff --git a/src/platformsupport/eglconvenience/eglconvenience.pro b/src/platformsupport/eglconvenience/eglconvenience.pro index 4301d63574..aae72e8e27 100644 --- a/src/platformsupport/eglconvenience/eglconvenience.pro +++ b/src/platformsupport/eglconvenience/eglconvenience.pro @@ -34,7 +34,7 @@ qtConfig(xlib) { qxlibeglintegration_p.h SOURCES += \ qxlibeglintegration.cpp - LIBS_PRIVATE += $$QMAKE_LIBS_X11 + QMAKE_USE_PRIVATE += xlib } CONFIG += egl diff --git a/src/platformsupport/glxconvenience/glxconvenience.pro b/src/platformsupport/glxconvenience/glxconvenience.pro index 58fa9fc479..8367dc5e31 100644 --- a/src/platformsupport/glxconvenience/glxconvenience.pro +++ b/src/platformsupport/glxconvenience/glxconvenience.pro @@ -6,7 +6,7 @@ CONFIG += static internal_module DEFINES += QT_NO_CAST_FROM_ASCII -LIBS_PRIVATE += $$QMAKE_LIBS_X11 +QMAKE_USE_PRIVATE += xlib HEADERS += qglxconvenience_p.h SOURCES += qglxconvenience.cpp From 3ee7aa72b78d892153439b668aa9f0a786d9f70e Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 21 Dec 2017 18:26:22 +0100 Subject: [PATCH 06/13] configure: atomize xcb-* tests properly xcb is a dependency which should be detected upfront. same for xlib. this also removes calls to functions coming from the dependencies from the tests (both because these calls prove nothing, and because at some point we will stop linking transitive deps). Change-Id: Iac77305eab33ea8ff5c71302cef980eb908d8403 Reviewed-by: Gatis Paeglis --- src/gui/configure.json | 55 ++++++++++--------- .../deviceintegration/eglfs_x11/eglfs_x11.pro | 2 +- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/gui/configure.json b/src/gui/configure.json index 123ef208a2..7b78954038 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -517,16 +517,14 @@ "xcb_xlib": { "label": "XCB Xlib", "test": { - "include": [ "xcb/xcb.h", "X11/Xlib.h", "X11/Xlib-xcb.h" ], - "main": [ - "Display *dpy = XOpenDisplay(\"\");", - "(void) XGetXCBConnection(dpy);" - ] + "include": "X11/Xlib-xcb.h", + "main": "(void) XGetXCBConnection((Display *)0);" }, "sources": [ - { "type": "pkgConfig", "args": "x11-xcb x11 xcb" }, - "-lxcb -lX11 -lX11-xcb" - ] + { "type": "pkgConfig", "args": "x11-xcb" }, + "-lX11-xcb" + ], + "use": "xcb xlib" }, "xcb_xkb": { "label": "XCB XKB >= 1.10", @@ -543,14 +541,15 @@ ] }, "sources": [ - { "type": "pkgConfig", "args": "xcb-xkb >= 1.10 xcb" }, - "-lxcb-xkb -lxcb" - ] + { "type": "pkgConfig", "args": "xcb-xkb >= 1.10" }, + "-lxcb-xkb" + ], + "use": "xcb" }, "xcb_render": { "label": "XCB XRender", "test": { - "include": [ "xcb/xcb.h", "xcb/render.h" ], + "include": "xcb/render.h", "tail": [ "// 'template' is used as a function argument name in xcb_renderutil.h", "#define template template_param", @@ -563,7 +562,7 @@ "main": [ "int primaryScreen = 0;", "xcb_generic_error_t *error = 0;", - "xcb_connection_t *connection = xcb_connect(\"\", &primaryScreen);", + "xcb_connection_t *connection = 0;", "xcb_render_query_pict_formats_cookie_t formatsCookie =", " xcb_render_query_pict_formats(connection);", "xcb_render_query_pict_formats_reply_t *formatsReply =", @@ -574,17 +573,18 @@ ] }, "sources": [ - { "type": "pkgConfig", "args": "xcb-renderutil xcb-render xcb" }, - "-lxcb-render-util -lxcb-render -lxcb" - ] + { "type": "pkgConfig", "args": "xcb-renderutil xcb-render" }, + "-lxcb-render-util -lxcb-render" + ], + "use": "xcb" }, "xcb_glx": { "label": "XCB GLX", "test": { - "include": [ "xcb/xcb.h", "xcb/glx.h" ], + "include": "xcb/glx.h", "main": [ "int primaryScreen = 0;", - "xcb_connection_t *connection = xcb_connect(\"\", &primaryScreen);", + "xcb_connection_t *connection = 0;", "xcb_generic_error_t *error = 0;", "xcb_glx_query_version_cookie_t xglx_query_cookie = xcb_glx_query_version(", " connection, XCB_GLX_MAJOR_VERSION, XCB_GLX_MINOR_VERSION);", @@ -592,17 +592,17 @@ ] }, "sources": [ - { "type": "pkgConfig", "args": "xcb-glx xcb" }, - "-lxcb-glx -lxcb" - ] + { "type": "pkgConfig", "args": "xcb-glx" }, + "-lxcb-glx" + ], + "use": "xcb" }, "xcb_xinput": { "label": "XCB XInput", "test": { - "include": [ "xcb/xcb.h", "xcb/xinput.h" ], + "include": "xcb/xinput.h", "main": [ - "int primaryScreen = 0;", - "xcb_connection_t *connection = xcb_connect(\"\", &primaryScreen);", + "xcb_connection_t *connection = 0;", "xcb_generic_error_t *error = 0;", "xcb_input_xi_query_version_cookie_t xinput_query_cookie = xcb_input_xi_query_version(", " connection, XCB_INPUT_MAJOR_VERSION, XCB_INPUT_MINOR_VERSION);", @@ -610,9 +610,10 @@ ] }, "sources": [ - { "type": "pkgConfig", "args": "xcb-xinput >= 1.12 xcb" }, - "-lxcb-xinput -lxcb" - ] + { "type": "pkgConfig", "args": "xcb-xinput >= 1.12" }, + "-lxcb-xinput" + ], + "use": "xcb" }, "xkbcommon": { "label": "xkbcommon >= 0.5.0", diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro index acbd1cc785..6b55918f03 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro @@ -8,7 +8,7 @@ DEFINES += QT_EGL_NO_X11 INCLUDEPATH += $$PWD/../../api CONFIG += egl -QMAKE_USE += xcb_xlib +QMAKE_USE += xcb_xlib xcb xlib SOURCES += $$PWD/qeglfsx11main.cpp \ $$PWD/qeglfsx11integration.cpp From 501ff0a18cff37cf0d237cd2b04b35fff1bd0837 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 21 Dec 2017 20:33:20 +0100 Subject: [PATCH 07/13] untangle the egl-x11 relationship in the build system egl-x11 is used in two places: - the eglfs-x11 plugin, which has a hard dependency on xcb-xlib - the xcb-egl plugin, which has a soft dependency on xcb-xlib that means that the egl-x11 configure test needs to be untangled from xcb, and that eglfs-x11 should be a separate feature with a proper dependency declaration. when the plugins that need egl-x11 are not built, it also makes no sense to build the respective integration in the egl_support module (even if it's possible to coax it into building), so adjust things accordingly. Change-Id: Ic729d0b7c893dd00844567329205c24ea2703033 Reviewed-by: Gatis Paeglis --- src/gui/configure.json | 11 ++++++++--- src/platformsupport/eglconvenience/eglconvenience.pro | 8 ++++---- .../eglfs/deviceintegration/deviceintegration.pro | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/gui/configure.json b/src/gui/configure.json index 7b78954038..7585e9c8d4 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -715,7 +715,7 @@ "// window and pixmap types will be different than what an X-based platform", "// plugin would expect." ], - "include": [ "EGL/egl.h", "xcb/xcb.h", "X11/Xlib.h", "X11/Xlib-xcb.h" ], + "include": [ "EGL/egl.h", "X11/Xlib.h" ], "main": [ "Display *dpy = EGL_DEFAULT_DISPLAY;", "EGLNativeDisplayType egldpy = XOpenDisplay(\"\");", @@ -725,7 +725,7 @@ "XCloseDisplay(dpy);" ] }, - "use": "egl xcb_xlib" + "use": "egl xlib" }, "egl-brcm": { "label": "Broadcom EGL (Raspberry Pi)", @@ -1229,6 +1229,11 @@ "condition": "config.integrity && features.eglfs && tests.egl-openwfd", "output": [ "privateFeature" ] }, + "eglfs_x11": { + "label": "EGLFS X11", + "condition": "features.eglfs && features.xcb && features.xcb-xlib && features.egl_x11", + "output": [ "privateFeature" ] + }, "gif": { "label": "GIF", "condition": "features.imageformatplugin", @@ -1709,7 +1714,7 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla "section": "EGLFS details", "condition": "features.eglfs", "entries": [ - "eglfs_openwfd", "eglfs_viv", "eglfs_viv_wl", "eglfs_rcar", "eglfs_egldevice", "eglfs_gbm", "eglfs_vsp2", "eglfs_mali", "eglfs_brcm", "egl_x11" + "eglfs_openwfd", "eglfs_viv", "eglfs_viv_wl", "eglfs_rcar", "eglfs_egldevice", "eglfs_gbm", "eglfs_vsp2", "eglfs_mali", "eglfs_brcm", "eglfs_x11" ] }, "linuxfb", "vnc", "mirclient", diff --git a/src/platformsupport/eglconvenience/eglconvenience.pro b/src/platformsupport/eglconvenience/eglconvenience.pro index aae72e8e27..df21f14697 100644 --- a/src/platformsupport/eglconvenience/eglconvenience.pro +++ b/src/platformsupport/eglconvenience/eglconvenience.pro @@ -26,15 +26,15 @@ qtConfig(opengl) { qeglpbuffer.cpp } -# Avoid X11 header collision, use generic EGL native types -DEFINES += QT_EGL_NO_X11 - -qtConfig(xlib) { +qtConfig(egl_x11) { HEADERS += \ qxlibeglintegration_p.h SOURCES += \ qxlibeglintegration.cpp QMAKE_USE_PRIVATE += xlib +} else { + # Avoid X11 header collision, use generic EGL native types + DEFINES += QT_EGL_NO_X11 } CONFIG += egl diff --git a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro index 919ecd01f6..360536d22f 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro +++ b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro @@ -1,7 +1,7 @@ TEMPLATE = subdirs QT_FOR_CONFIG += gui-private -qtConfig(egl_x11): SUBDIRS += eglfs_x11 +qtConfig(eglfs_x11): SUBDIRS += eglfs_x11 qtConfig(eglfs_gbm): SUBDIRS *= eglfs_kms_support eglfs_kms qtConfig(eglfs_egldevice): SUBDIRS *= eglfs_kms_support eglfs_kms_egldevice qtConfig(eglfs_vsp2): SUBDIRS += eglfs_kms_vsp2 From c4ee12589122923e680e8dd359c30f6dde370f54 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 27 Nov 2018 10:47:52 +0100 Subject: [PATCH 08/13] Set QScroller's parent to its widget, for memory management If the widget to which the scroller was assigned is deleted, the QScroller ought to be deleted too, to avoid filtering events and then following a dangling pointer while trying to react. Fixes: QTBUG-71232 Change-Id: I62680df8d84fb630df1bd8c482df099989457542 Reviewed-by: Friedemann Kleint Reviewed-by: Robert Griebl --- src/widgets/util/qscroller.cpp | 1 + .../widgets/util/qscroller/tst_qscroller.cpp | 38 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/widgets/util/qscroller.cpp b/src/widgets/util/qscroller.cpp index abb203b8cc..1e84237253 100644 --- a/src/widgets/util/qscroller.cpp +++ b/src/widgets/util/qscroller.cpp @@ -488,6 +488,7 @@ QScroller::QScroller(QObject *target) : d_ptr(new QScrollerPrivate(this, target)) { Q_ASSERT(target); // you can't create a scroller without a target in any normal way + setParent(target); Q_D(QScroller); d->init(); } diff --git a/tests/auto/widgets/util/qscroller/tst_qscroller.cpp b/tests/auto/widgets/util/qscroller/tst_qscroller.cpp index fac13c7074..8bdd4b4783 100644 --- a/tests/auto/widgets/util/qscroller/tst_qscroller.cpp +++ b/tests/auto/widgets/util/qscroller/tst_qscroller.cpp @@ -125,6 +125,7 @@ private slots: void scrollTo(); void scroll(); void overshoot(); + void multipleWindows(); private: QTouchDevice *m_touchScreen = QTest::createTouchDevice(); @@ -373,7 +374,7 @@ void tst_QScroller::scrollTo() void tst_QScroller::scroll() { -#ifndef QT_NO_GESTURES +#if QT_CONFIG(gestures) && QT_CONFIG(scroller) // -- good case. normal scroll tst_QScrollerWidget *sw = new tst_QScrollerWidget(); sw->scrollArea = QRectF(0, 0, 1000, 1000); @@ -413,7 +414,7 @@ void tst_QScroller::scroll() void tst_QScroller::overshoot() { -#ifndef QT_NO_GESTURES +#if QT_CONFIG(gestures) && QT_CONFIG(scroller) tst_QScrollerWidget *sw = new tst_QScrollerWidget(); sw->scrollArea = QRectF(0, 0, 1000, 1000); QScroller::grabGesture(sw, QScroller::TouchGesture); @@ -504,6 +505,39 @@ void tst_QScroller::overshoot() #endif } +void tst_QScroller::multipleWindows() +{ +#if QT_CONFIG(gestures) && QT_CONFIG(scroller) + QScopedPointer sw1(new tst_QScrollerWidget()); + sw1->scrollArea = QRectF(0, 0, 1000, 1000); + QScroller::grabGesture(sw1.data(), QScroller::TouchGesture); + sw1->setGeometry(100, 100, 400, 300); + QScroller *s1 = QScroller::scroller(sw1.data()); + kineticScroll(sw1.data(), QPointF(500, 500), QPoint(0, 0), QPoint(100, 100), QPoint(200, 200)); + // now we should be scrolling + QTRY_COMPARE( s1->state(), QScroller::Scrolling ); + + // That was fun! Do it again! + QScopedPointer sw2(new tst_QScrollerWidget()); + sw2->scrollArea = QRectF(0, 0, 1000, 1000); + QScroller::grabGesture(sw2.data(), QScroller::TouchGesture); + sw2->setGeometry(100, 100, 400, 300); + QScroller *s2 = QScroller::scroller(sw2.data()); + kineticScroll(sw2.data(), QPointF(500, 500), QPoint(0, 0), QPoint(100, 100), QPoint(200, 200)); + // now we should be scrolling + QTRY_COMPARE( s2->state(), QScroller::Scrolling ); + + // wait for both to stop + QTRY_VERIFY(s1->state() != QScroller::Scrolling); + QTRY_VERIFY(s2->state() != QScroller::Scrolling); + + sw1.reset(); // destroy one window + sw2->reset(); // reset the other scroller's internal state + // make sure we can still scroll the remaining one without crashing (QTBUG-71232) + kineticScroll(sw2.data(), QPointF(500, 500), QPoint(0, 0), QPoint(100, 100), QPoint(200, 200)); +#endif +} + QTEST_MAIN(tst_QScroller) #include "tst_qscroller.moc" From 25231c40489e54d57998fa44385ad832cc32b30d Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Mon, 3 Dec 2018 19:36:54 +0100 Subject: [PATCH 09/13] QToolButton: Don't elide text if an icon is present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous fix which adds an automatic text elision when the QToolButton is not large enough brought up an inconsistency between QToolButton::sizeHint() and QCommonStyle::drawControl(). Fix it by syncing the magic numbers between QToolButton::sizeHint() and QCommonStyle::drawControl(). Fixes: QTBUG-72226 Change-Id: If4a76792cb97bcdb918e18c6b29cb637730acec0 Reviewed-by: André Hartmann Reviewed-by: Alessandro Portale Reviewed-by: Thorbjørn Lund Martsum --- src/widgets/styles/qcommonstyle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index bb623d9c04..10dfad2754 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -1654,7 +1654,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, alignment |= Qt::TextHideMnemonic; if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) { - pr.setHeight(pmSize.height() + 6); + pr.setHeight(pmSize.height() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint() tr.adjust(0, pr.height() - 1, 0, -1); pr.translate(shiftX, shiftY); if (!hasArrow) { @@ -1664,7 +1664,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, } alignment |= Qt::AlignCenter; } else { - pr.setWidth(pmSize.width() + 8); + pr.setWidth(pmSize.width() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint() tr.adjust(pr.width(), 0, 0, 0); pr.translate(shiftX, shiftY); if (!hasArrow) { From a71f50edc6431a7d5a8b4a4836e98ca59e6ad7ae Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 7 Dec 2018 12:07:53 +0000 Subject: [PATCH 10/13] Revert "Ensure alignment of image-data" This reverts commit ae8389e19c5804c867b2981311c623003a691474. The result of malloc should be aligned in any case, and this change conflicts with the use of realloc on the data elsewhere. Change-Id: I01773132b240614a2656dd3013490b0df9cd14a7 Reviewed-by: Kirill Burtsev Reviewed-by: Thiago Macieira --- src/gui/image/qimage.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index da963adae6..0105f1decd 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -149,10 +149,7 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format) d->bytes_per_line = params.bytesPerLine; d->nbytes = params.totalSize; - if (depth == 64) - d->data = (uchar *)new (std::nothrow) quint64[d->nbytes / sizeof(quint64)]; - else // nbytes is known to already be a multipla of 4: - d->data = (uchar *)new (std::nothrow) quint32[d->nbytes / sizeof(quint32)]; + d->data = (uchar *)malloc(d->nbytes); if (!d->data) return nullptr; @@ -168,13 +165,8 @@ QImageData::~QImageData() if (is_cached) QImagePixmapCleanupHooks::executeImageHooks((((qint64) ser_no) << 32) | ((qint64) detach_no)); delete paintEngine; - if (data && own_data) { - // Casting to avoid being theoretically UB: - if (depth == 64) - delete[] (quint64 *)data; - else - delete[] (quint32 *)data; - } + if (data && own_data) + free(data); data = 0; } From e12aad05f039ddaefd444f80246845090ef9ce13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 28 Nov 2018 16:56:44 +0100 Subject: [PATCH 11/13] Add manual test case for verifying our text rendering Allows comparing Qt's text rendering to the native rendering. Change-Id: I56f015fb64df3f70c33db58891876c325cbbc55d Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../manual/textrendering/nativetext/main.cpp | 310 ++++++++++++++++++ .../textrendering/nativetext/nativetext.pro | 7 + tests/manual/textrendering/textrendering.pro | 3 +- 3 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 tests/manual/textrendering/nativetext/main.cpp create mode 100644 tests/manual/textrendering/nativetext/nativetext.pro diff --git a/tests/manual/textrendering/nativetext/main.cpp b/tests/manual/textrendering/nativetext/main.cpp new file mode 100644 index 0000000000..5c7621e61f --- /dev/null +++ b/tests/manual/textrendering/nativetext/main.cpp @@ -0,0 +1,310 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#ifdef Q_OS_DARWIN +#include +#include +#include +#include +#include +#endif + +static int s_mode; +static QString s_text = QString::fromUtf8("The quick brown \xF0\x9F\xA6\x8A jumps over the lazy \xF0\x9F\x90\xB6"); + +class TextRenderer : public QWidget +{ + Q_OBJECT +public: + enum RenderingMode { QtRendering, NativeRendering }; + Q_ENUM(RenderingMode); + + TextRenderer(qreal pointSize, const QString &text, const QColor &textColor = QColor(), const QColor &bgColor = QColor()) + : m_text(text) + { + if (pointSize) { + QFont f = font(); + f.setPointSize(pointSize); + setFont(f); + } + + if (textColor.isValid()) { + QPalette p = palette(); + p.setColor(QPalette::Text, textColor); + setPalette(p); + } + + if (bgColor.isValid()) { + QPalette p = palette(); + p.setColor(QPalette::Window, bgColor); + setPalette(p); + } + } + + QString text() const + { + return !m_text.isNull() ? m_text : s_text; + } + + QSize sizeHint() const override + { + QFontMetrics fm = fontMetrics(); + return QSize(fm.boundingRect(text()).width(), fm.height()); + } + + bool event(QEvent * event) override + { + if (event->type() == QEvent::ToolTip) { + QString toolTip; + QDebug debug(&toolTip); + debug << "textColor =" << palette().color(QPalette::Text) << "bgColor =" << palette().color(QPalette::Window); + setToolTip(toolTip); + } + + return QWidget::event(event); + } + + void paintEvent(QPaintEvent *) override + { + QImage image(size() * devicePixelRatio(), QImage::Format_ARGB32_Premultiplied); + image.setDevicePixelRatio(devicePixelRatio()); + + QPainter p(&image); + p.fillRect(QRect(0, 0, image.width(), image.height()), palette().window().color()); + + const int ascent = fontMetrics().ascent(); + + p.setPen(Qt::magenta); + p.drawLine(QPoint(0, ascent), QPoint(width(), ascent)); + p.end(); + + if (s_mode == QtRendering) + renderQtText(image); + else + renderNativeText(image); + + QPainter wp(this); + wp.drawImage(QPoint(0, 0), image); + } + + void renderQtText(QImage &image) + { + QPainter p(&image); + + const int ascent = fontMetrics().ascent(); + + p.setPen(palette().text().color()); + + QFont f = font(); + f.resolve(-1); + p.setFont(f); + + p.drawText(QPoint(0, ascent), text()); + } + + void renderNativeText(QImage &image) + { +#ifdef Q_OS_DARWIN + QMacAutoReleasePool pool; + QMacCGContext ctx(&image); + + const auto *fontEngine = QFontPrivate::get(font())->engineForScript(QChar::Script_Common); + Q_ASSERT(fontEngine); + if (fontEngine->type() == QFontEngine::Multi) { + fontEngine = static_cast(fontEngine)->engine(0); + Q_ASSERT(fontEngine); + } + Q_ASSERT(fontEngine->type() == QFontEngine::Mac); + + QColor textColor = palette().text().color(); + auto nsColor = [NSColor colorWithSRGBRed:textColor.redF() + green:textColor.greenF() + blue:textColor.blueF() + alpha:textColor.alphaF()]; + + if (font().styleStrategy() & QFont::NoAntialias) + CGContextSetShouldAntialias(ctx, false); + + // Retain count already tracked by QMacCGContext above + NSGraphicsContext.currentContext = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:YES]; + [text().toNSString() drawAtPoint:CGPointZero withAttributes:@{ + NSFontAttributeName : (NSFont *)fontEngine->handle(), + NSForegroundColorAttributeName : nsColor + }]; + NSGraphicsContext.currentContext = nil; +#endif + } + +public: + + RenderingMode m_mode = QtRendering; + QString m_text; +}; + +class TestWidget : public QWidget +{ + Q_OBJECT +public: + TestWidget() + { + auto *mainLayout = new QVBoxLayout; + + m_previews = new QWidget; + m_previews->setLayout(new QHBoxLayout); + + for (int i = 0; i < 6; ++i) { + auto *layout = new QVBoxLayout; + QString text; + if (i > 0) + text = "ABC"; + + QPair color = [i] { + switch (i) { + case 0: return qMakePair(QColor(), QColor()); + case 1: return qMakePair(QColor(Qt::black), QColor(Qt::white)); + case 2: return qMakePair(QColor(Qt::white), QColor(Qt::black)); + case 3: return qMakePair(QColor(Qt::green), QColor(Qt::red)); + case 4: return qMakePair(QColor(0, 0, 0, 128), QColor(Qt::white)); + case 5: return qMakePair(QColor(255, 255, 255, 128), QColor(Qt::black)); + default: return qMakePair(QColor(), QColor()); + } + }(); + + layout->addWidget(new TextRenderer(12, text, color.first, color.second)); + layout->addWidget(new TextRenderer(24, text, color.first, color.second)); + layout->addWidget(new TextRenderer(36, text, color.first, color.second)); + layout->addWidget(new TextRenderer(48, text, color.first, color.second)); + static_cast(m_previews->layout())->addLayout(layout); + } + + mainLayout->addWidget(m_previews); + + auto *controls = new QHBoxLayout; + auto *lineEdit = new QLineEdit(s_text); + connect(lineEdit, &QLineEdit::textChanged, [&](const QString &text) { + s_text = text; + for (TextRenderer *renderer : m_previews->findChildren()) + renderer->updateGeometry(); + }); + controls->addWidget(lineEdit); + + auto *colorButton = new QPushButton("Color..."); + connect(colorButton, &QPushButton::clicked, [&] { + auto *colorDialog = new QColorDialog(this); + colorDialog->setOptions(QColorDialog::NoButtons | QColorDialog::ShowAlphaChannel); + colorDialog->setModal(false); + connect(colorDialog, &QColorDialog::currentColorChanged, [&](const QColor &color) { + QPalette p = palette(); + p.setColor(QPalette::Text, color); + setPalette(p); + }); + colorDialog->setCurrentColor(palette().text().color()); + colorDialog->setVisible(true); + }); + controls->addWidget(colorButton); + auto *fontButton = new QPushButton("Font..."); + connect(fontButton, &QPushButton::clicked, [&] { + auto *fontDialog = new QFontDialog(this); + fontDialog->setOptions(QFontDialog::NoButtons); + fontDialog->setModal(false); + fontDialog->setCurrentFont(m_previews->font()); + connect(fontDialog, &QFontDialog::currentFontChanged, [&](const QFont &font) { + m_previews->setFont(font); + }); + fontDialog->setVisible(true); + }); + controls->addWidget(fontButton); + + auto *aaButton = new QCheckBox("NoAntialias"); + connect(aaButton, &QCheckBox::stateChanged, [&] { + for (TextRenderer *renderer : m_previews->findChildren()) { + QFont font = renderer->font(); + font.setStyleStrategy(QFont::StyleStrategy(font.styleStrategy() ^ QFont::NoAntialias)); + renderer->setFont(font); + } + }); + controls->addWidget(aaButton); + + auto *subpixelAAButton = new QCheckBox("NoSubpixelAntialias"); + connect(subpixelAAButton, &QCheckBox::stateChanged, [&] { + for (TextRenderer *renderer : m_previews->findChildren()) { + QFont font = renderer->font(); + font.setStyleStrategy(QFont::StyleStrategy(font.styleStrategy() ^ QFont::NoSubpixelAntialias)); + renderer->setFont(font); + } + }); + controls->addWidget(subpixelAAButton); + controls->addStretch(); + + mainLayout->addLayout(controls); + + mainLayout->setSizeConstraint(QLayout::SetFixedSize); + setLayout(mainLayout); + + setMode(TextRenderer::QtRendering); + setFocusPolicy(Qt::StrongFocus); + setFocus(); + } + + void setMode(TextRenderer::RenderingMode mode) + { + s_mode = mode; + setWindowTitle(s_mode == TextRenderer::QtRendering ? "Qt" : "Native"); + + for (TextRenderer *renderer : m_previews->findChildren()) + renderer->update(); + } + + void mousePressEvent(QMouseEvent *) override + { + setMode(TextRenderer::RenderingMode(!s_mode)); + } + + void keyPressEvent(QKeyEvent *e) override + { + if (e->key() == Qt::Key_Space) + setMode(TextRenderer::RenderingMode(!s_mode)); + } + + QWidget *m_previews; +}; + +int main(int argc, char **argv) +{ + qputenv("QT_MAX_CACHED_GLYPH_SIZE", "97"); + QApplication app(argc, argv); + + TestWidget widget; + widget.show(); + return app.exec(); +} + +#include "main.moc" + diff --git a/tests/manual/textrendering/nativetext/nativetext.pro b/tests/manual/textrendering/nativetext/nativetext.pro new file mode 100644 index 0000000000..fb3e3799e7 --- /dev/null +++ b/tests/manual/textrendering/nativetext/nativetext.pro @@ -0,0 +1,7 @@ +QT += widgets core-private gui-private +SOURCES += main.cpp +CONFIG -= app_bundle +darwin { + QMAKE_CXXFLAGS += -x objective-c++ + LIBS += -framework Foundation -framework CoreGraphics -framework AppKit +} diff --git a/tests/manual/textrendering/textrendering.pro b/tests/manual/textrendering/textrendering.pro index 92f0741bf3..14806e416c 100644 --- a/tests/manual/textrendering/textrendering.pro +++ b/tests/manual/textrendering/textrendering.pro @@ -1,4 +1,5 @@ TEMPLATE=subdirs SUBDIRS = glyphshaping \ - textperformance + textperformance \ + nativetext From 2e715c31ed3a37fc196e97d4c58d0e277b1b9215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 5 Dec 2018 17:10:34 +0100 Subject: [PATCH 12/13] Allow overriding the maximum cached glyph size via the environment Useful for testing. Change-Id: I8cfd4453018cba0301287ad6a1c15a88cdc33c1c Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/painting/qpaintengineex.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 9f07af92e4..f4cbf15fc7 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -1090,9 +1090,14 @@ bool QPaintEngineEx::shouldDrawCachedGlyphs(QFontEngine *fontEngine, const QTran if (fontEngine->glyphFormat == QFontEngine::Format_ARGB) return true; + static const int maxCachedGlyphSizeSquared = std::pow([]{ + if (int env = qEnvironmentVariableIntValue("QT_MAX_CACHED_GLYPH_SIZE")) + return env; + return QT_MAX_CACHED_GLYPH_SIZE; + }(), 2); + qreal pixelSize = fontEngine->fontDef.pixelSize; - return (pixelSize * pixelSize * qAbs(m.determinant())) < - QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE; + return (pixelSize * pixelSize * qAbs(m.determinant())) < maxCachedGlyphSizeSquared; } QT_END_NAMESPACE From d36a4fc19709e6047fe846b36731b59909218b6d Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 12 Sep 2018 23:06:40 -0700 Subject: [PATCH 13/13] Optimize further the loading of 8 Latin 1 characters This is important when AVX is enabled, which makes the VMOVQ load and the VPMOVZXBW instruction be combined into a single VPMOVZXBW with direct memory access. This is guaranteed to only read 8 bytes, so it's safe even close to the end of a page. Clang and ICC do combine the instructions like we want and I have filed a request for GCC to do so too[1]. AVX was first introduced in 2011, so plenty of computers today would benefit from this. [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87317 Change-Id: I8f261579aad648fdb4f0fffd1553e08e90df3171 Reviewed-by: Allan Sandfeld Jensen --- src/corelib/tools/qstring.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index edb9983c33..d20c46774d 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -415,6 +415,21 @@ static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval) return true; } + +static Q_ALWAYS_INLINE __m128i mm_load8_zero_extend(const void *ptr) +{ + const __m128i *dataptr = static_cast(ptr); +#if defined(__SSE4_1__) + // use a MOVQ followed by PMOVZXBW + // if AVX2 is present, these should combine into a single VPMOVZXBW instruction + __m128i data = _mm_loadl_epi64(dataptr); + return _mm_cvtepu8_epi16(data); +# else + // use MOVQ followed by PUNPCKLBW + __m128i data = _mm_loadl_epi64(dataptr); + return _mm_unpacklo_epi8(data, _mm_setzero_si128()); +# endif +} #endif // Note: ptr on output may be off by one and point to a preceding US-ASCII @@ -585,8 +600,7 @@ void qt_from_latin1(ushort *dst, const char *str, size_t size) Q_DECL_NOTHROW // we're going to read str[offset..offset+7] (8 bytes) if (str + offset + 7 < e) { - const __m128i chunk = _mm_loadl_epi64(reinterpret_cast(str + offset)); - const __m128i unpacked = _mm_unpacklo_epi8(chunk, _mm_setzero_si128()); + const __m128i unpacked = mm_load8_zero_extend(str + offset); _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + offset), unpacked); offset += 8; } @@ -1044,8 +1058,7 @@ static int ucstrncmp(const QChar *a, const uchar *c, size_t l) // we'll read uc[offset..offset+7] (16 bytes) and c[offset..offset+7] (8 bytes) if (uc + offset + 7 < e) { // same, but we're using an 8-byte load - __m128i chunk = _mm_loadl_epi64((const __m128i*)(c + offset)); - __m128i secondHalf = _mm_unpacklo_epi8(chunk, nullmask); + __m128i secondHalf = mm_load8_zero_extend(c + offset); __m128i ucdata = _mm_loadu_si128((const __m128i*)(uc + offset)); __m128i result = _mm_cmpeq_epi16(secondHalf, ucdata);