Compare commits

...
Sign in to create a new pull request.

16 commits

Author SHA1 Message Date
Jan Grulich
082bad2484 Fix crash in QWaylandShmBackingStore::scroll() 2025-12-22 16:15:39 +01:00
Jan Grulich
af0ef1e954 Re-add wayland fixes for mouse scrolling 2025-12-08 08:17:21 +01:00
Jan Grulich
67c126dc18 6.10.1 2025-11-20 08:59:53 +01:00
Jan Grulich
2ff34253dc Backport wayland fixes for mouse scrolling 2025-11-10 11:20:53 +01:00
Jan Grulich
045b22d4d6 Backport: Wayland - convey preference for server side decorations 2025-10-29 14:29:28 +01:00
Jan Grulich
05ee0b98b4 6.10.0 2025-10-07 10:34:47 +02:00
Gwyn Ciesla
07c9cbcba0 Firebird 5 rebuild 2025-09-30 11:07:46 -05:00
Jan Grulich
1646c99cab 6.10.0 RC 2025-09-25 12:17:25 +02:00
Jan Grulich
060d33bcdd 6.9.2 2025-08-28 13:01:40 +02:00
František Zatloukal
362bc3dbd4 Rebuilt for icu 77.1 2025-08-05 23:55:00 +02:00
Adam Williamson
0e85496669 Adjust for https://fedoraproject.org/wiki/Changes/dropingOfCertPemFile removals
Backport of https://codereview.qt-project.org/c/qt/qtbase/+/664056
2025-07-28 14:25:11 -07:00
Fedora Release Engineering
ed748d94e8 Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild 2025-07-25 11:33:58 +00:00
Jan Grulich
fe42bba4fc 6.9.1 2025-06-02 13:34:16 +02:00
Jan Grulich
ba0d907174 Fix possible crash in FontConfig database 2025-04-28 08:26:13 +02:00
Jan Grulich
49cf38aa7e 6.9.0 2025-04-02 09:58:38 +02:00
Jan Grulich
e21e53a974 6.9.0 RC 2025-03-21 13:30:18 +01:00
23 changed files with 903 additions and 26361 deletions

7
.gitignore vendored
View file

@ -32,3 +32,10 @@
/qtbase-everywhere-src-6.8.0.tar.xz
/qtbase-everywhere-src-6.8.1.tar.xz
/qtbase-everywhere-src-6.8.2.tar.xz
/qtbase-everywhere-src-6.9.0-rc.tar.xz
/qtbase-everywhere-src-6.9.0.tar.xz
/qtbase-everywhere-src-6.9.1.tar.xz
/qtbase-everywhere-src-6.9.2.tar.xz
/qtbase-everywhere-src-6.10.0-rc.tar.xz
/qtbase-everywhere-src-6.10.0.tar.xz
/qtbase-everywhere-src-6.10.1.tar.xz

View file

@ -41,11 +41,13 @@ BuildRequires: pkgconfig(libsystemd)
#global tests 1
#global unstable 0
%global prerelease rc2
%if 0%{?unstable}
%global prerelease rc
%endif
Name: qt6-qtbase
Summary: Qt6 - QtBase components
Version: 6.8.2
Version: 6.10.1
Release: 3%{?dist}
License: LGPL-3.0-only OR GPL-3.0-only WITH Qt-GPL-exception-1.0
@ -96,21 +98,11 @@ Patch56: qtbase-mysql.patch
Patch58: qtbase-libglvnd.patch
# upstream patches
Patch100: qtbase-qtlocale-try-to-survive-being-created-during-application-shut-down.patch
Patch101: qtbase-qsystemlocale-bail-out-if-accessed-post-destruction.patch
Patch102: qtbase-qlibraryinfo-speedup-checking-if-qt-conf-resource-exists.patch
## upstream patches from Qt 6.9
Patch150: qtbase-extract-emoji-data-from-unicode-files.patch
Patch151: qtbase-introduce-emoji-segmenter-to-3rdparty-code.patch
Patch152: qtbase-use-emoji-segmenter-to-apply-emoji-fonts-automatically.patch
Patch153: qtbase-fix-regression-when-looking-up-fallback-fonts.patch
Patch154: qtbase-skip-ad-hoc-handling-of-variation-selector-in-font-merging.patch
Patch155: qtbase-fontconfig-dont-register-hardcoded-fonts-as-color-fonts.patch
Patch156: qtbase-request-actual-font-family-request-in-final-color-font-fail-safe.patch
Patch157: qtbase-fontconfig-fix-detection-of-color-fonts.patch
Patch158: qtbase-support-variation-selector-when-emoji-segmenter-is-disabled.patch
Patch159: qtbase-treat-variation-selectors-as-ignorable-chars.patch
Patch100: qtbase-wayland-convey-preference-for-server-side-decorations.patch
Patch101: qtbase-wayland-compress-high-frequency-mouse-events.patch
Patch102: qtbase-wayland-optimize-scroll-operations.patch
Patch103: qtbase-wayland-enable-event-compression-and-fix-scroll-end-event.patch
Patch104: qtbase-wayland-fix-crash-in-qwaylandshmbackingstore-scroll.patch
# Do not check any files in %%{_qt6_plugindir}/platformthemes/ for requires.
# Those themes are there for platform integration. If the required libraries are
@ -181,7 +173,13 @@ BuildRequires: pkgconfig(vulkan)
BuildRequires: pkgconfig(egl)
BuildRequires: pkgconfig(gbm)
BuildRequires: pkgconfig(libglvnd)
BuildRequires: pkgconfig(xrender)
BuildRequires: pkgconfig(x11)
BuildRequires: pkgconfig(wayland-scanner)
BuildRequires: pkgconfig(wayland-server)
BuildRequires: pkgconfig(wayland-client)
BuildRequires: pkgconfig(wayland-cursor)
BuildRequires: pkgconfig(wayland-egl)
%global sqlite 1
BuildRequires: pkgconfig(sqlite3) >= 3.7
@ -321,7 +319,6 @@ Requires: %{name}%{?_isa} = %{version}-%{release}
Summary: Qt6 GUI-related libraries
Requires: %{name}%{?_isa} = %{version}-%{release}
Recommends: mesa-dri-drivers%{?_isa}
Recommends: qt6-qtwayland%{?_isa}
# Required for some locales: https://pagure.io/fedora-kde/SIG/issue/311
Recommends: qt6-qttranslations
Obsoletes: adwaita-qt6 <= 1.4.2
@ -443,7 +440,7 @@ translationdir=%{_qt6_translationdir}
Name: Qt6
Description: Qt6 Configuration
Version: 6.8.2
Version: 6.10.1
EOF
# rpm macros
@ -514,7 +511,10 @@ rm -r %{buildroot}%{_qt6_libdir}/cmake/Qt6ExamplesAssetDownloaderPrivate
rm -r %{buildroot}%{_qt6_headerdir}/QtExamplesAssetDownloader
rm %{buildroot}%{_qt6_descriptionsdir}/ExamplesAssetDownloaderPrivate.json
rm %{buildroot}%{_qt6_libdir}/libQt6ExamplesAssetDownloader.*
rm %{buildroot}%{_qt6_libdir}/qt6/metatypes/qt6examplesassetdownloaderprivate_*_metatypes.json
rm %{buildroot}%{_qt6_libdir}/qt6/metatypes/qt6examplesassetdownloaderprivate_metatypes.json
# These shouldn't be probably installed
rm -r %{buildroot}%{_qt6_libdir}/cmake/Qt6/3rdparty/extra-cmake-modules/*.patch
# This is only for Apple platforms and has a python2 dep
rm -r %{buildroot}%{_qt6_mkspecsdir}/features/uikit
@ -609,6 +609,11 @@ make check -k ||:
%dir %{_qt6_libdir}/cmake/Qt6PrintSupport
%dir %{_qt6_libdir}/cmake/Qt6Sql
%dir %{_qt6_libdir}/cmake/Qt6Test
%dir %{_qt6_libdir}/cmake/Qt6WaylandClient/
%dir %{_qt6_libdir}/cmake/Qt6WaylandClientPrivate
%dir %{_qt6_libdir}/cmake/Qt6WaylandGlobalPrivate/
%dir %{_qt6_libdir}/cmake/Qt6WaylandScannerTools/
%dir %{_qt6_libdir}/cmake/Qt6WlShellIntegrationPrivate/
%dir %{_qt6_libdir}/cmake/Qt6Widgets
%dir %{_qt6_libdir}/cmake/Qt6WidgetsTools
%dir %{_qt6_libdir}/cmake/Qt6Xml
@ -645,6 +650,7 @@ make check -k ||:
%{_qt6_libexecdir}/qvkgen
%{_qt6_libexecdir}/rcc
%{_qt6_libexecdir}/uic
%{_qt6_libexecdir}/qtwaylandscanner
%{_qt6_headerdir}/QtConcurrent/
%{_qt6_headerdir}/QtCore/
%{_qt6_headerdir}/QtDBus/
@ -655,6 +661,9 @@ make check -k ||:
%{_qt6_headerdir}/QtPrintSupport/
%{_qt6_headerdir}/QtSql/
%{_qt6_headerdir}/QtTest/
%{_qt6_headerdir}/QtWaylandClient/
%{_qt6_headerdir}/QtWaylandGlobal/
%{_qt6_headerdir}/QtWlShellIntegration/
%{_qt6_headerdir}/QtWidgets/
%{_qt6_headerdir}/QtXcb/
%{_qt6_headerdir}/QtXml/
@ -678,14 +687,19 @@ make check -k ||:
%{_qt6_libdir}/libQt6Sql.so
%{_qt6_libdir}/libQt6Test.prl
%{_qt6_libdir}/libQt6Test.so
%{_qt6_libdir}/libQt6WaylandClient.so
%{_qt6_libdir}/libQt6WlShellIntegration.so
%{_qt6_libdir}/libQt6WaylandClient.prl
%{_qt6_libdir}/libQt6WlShellIntegration.prl
%{_qt6_libdir}/libQt6Widgets.prl
%{_qt6_libdir}/libQt6Widgets.so
%{_qt6_libdir}/libQt6XcbQpa.prl
%{_qt6_libdir}/libQt6XcbQpa.so
%{_qt6_libdir}/libQt6XcbQpa.so
%{_qt6_libdir}/libQt6Xml.prl
%{_qt6_libdir}/libQt6Xml.so
%{_qt6_libdir}/cmake/Qt6/3rdparty/extra-cmake-modules/REUSE.toml
%{_qt6_libdir}/cmake/Qt6/3rdparty/kwin/REUSE.toml
%{_qt6_libdir}/cmake/Qt6/*.in
%{_qt6_libdir}/cmake/Qt6/*.h.in
%{_qt6_libdir}/cmake/Qt6/*.cmake
%{_qt6_libdir}/cmake/Qt6/*.cmake.in
@ -727,6 +741,11 @@ make check -k ||:
%{_qt6_libdir}/cmake/Qt6Sql/Qt6Sql*.cmake
%{_qt6_libdir}/cmake/Qt6Sql/Qt6QSQLiteDriverPlugin*.cmake
%{_qt6_libdir}/cmake/Qt6Test/*.cmake
%{_qt6_libdir}/cmake/Qt6WaylandClient/*.cmake
%{_qt6_libdir}/cmake/Qt6WaylandClientPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6WaylandGlobalPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6WaylandScannerTools/*.cmake
%{_qt6_libdir}/cmake/Qt6WlShellIntegrationPrivate/
%{_qt6_libdir}/cmake/Qt6Widgets/*.cmake
%{_qt6_libdir}/cmake/Qt6WidgetsTools/*.cmake
%{_qt6_libdir}/cmake/Qt6Xml/*.cmake
@ -740,20 +759,23 @@ make check -k ||:
%{_qt6_descriptionsdir}/PrintSupport.json
%{_qt6_descriptionsdir}/Sql.json
%{_qt6_descriptionsdir}/Test.json
%{_qt6_descriptionsdir}/WaylandClient.json
%{_qt6_descriptionsdir}/WaylandGlobalPrivate.json
%{_qt6_descriptionsdir}/WlShellIntegrationPrivate.json
%{_qt6_descriptionsdir}/Widgets.json
%{_qt6_descriptionsdir}/Xml.json
%{_qt6_metatypesdir}/qt6concurrent_*_metatypes.json
%{_qt6_metatypesdir}/qt6core_*_metatypes.json
%{_qt6_metatypesdir}/qt6dbus_*_metatypes.json
%{_qt6_metatypesdir}/qt6gui_*_metatypes.json
%{_qt6_metatypesdir}/qt6network_*_metatypes.json
%{_qt6_metatypesdir}/qt6opengl_*_metatypes.json
%{_qt6_metatypesdir}/qt6openglwidgets_*_metatypes.json
%{_qt6_metatypesdir}/qt6printsupport_*_metatypes.json
%{_qt6_metatypesdir}/qt6sql_*_metatypes.json
%{_qt6_metatypesdir}/qt6test_*_metatypes.json
%{_qt6_metatypesdir}/qt6widgets_*_metatypes.json
%{_qt6_metatypesdir}/qt6xml_*_metatypes.json
%{_qt6_metatypesdir}/qt6concurrent_metatypes.json
%{_qt6_metatypesdir}/qt6core_metatypes.json
%{_qt6_metatypesdir}/qt6dbus_metatypes.json
%{_qt6_metatypesdir}/qt6gui_metatypes.json
%{_qt6_metatypesdir}/qt6network_metatypes.json
%{_qt6_metatypesdir}/qt6opengl_metatypes.json
%{_qt6_metatypesdir}/qt6openglwidgets_metatypes.json
%{_qt6_metatypesdir}/qt6printsupport_metatypes.json
%{_qt6_metatypesdir}/qt6sql_metatypes.json
%{_qt6_metatypesdir}/qt6test_metatypes.json
%{_qt6_metatypesdir}/qt6widgets_metatypes.json
%{_qt6_metatypesdir}/qt6xml_metatypes.json
%{_qt6_libdir}/pkgconfig/*.pc
%{_qt6_mkspecsdir}/*
## private-devel globs
@ -763,10 +785,34 @@ make check -k ||:
%{_qt6_headerdir}/QtEglFSDeviceIntegration
%{_qt6_headerdir}/QtEglFsKmsGbmSupport
%{_qt6_headerdir}/QtEglFsKmsSupport
%dir %{_qt6_libdir}/cmake/Qt6CorePrivate
%dir %{_qt6_libdir}/cmake/Qt6DBusPrivate
%dir %{_qt6_libdir}/cmake/Qt6GuiPrivate
%dir %{_qt6_libdir}/cmake/Qt6NetworkPrivate
%dir %{_qt6_libdir}/cmake/Qt6OpenGLPrivate
%dir %{_qt6_libdir}/cmake/Qt6PrintSupportPrivate
%dir %{_qt6_libdir}/cmake/Qt6SqlPrivate
%dir %{_qt6_libdir}/cmake/Qt6TestInternalsPrivate
%dir %{_qt6_libdir}/cmake/Qt6TestInternalsPrivate/3rdparty/cmake
%dir %{_qt6_libdir}/cmake/Qt6TestPrivate
%dir %{_qt6_libdir}/cmake/Qt6WidgetsPrivate
%dir %{_qt6_libdir}/cmake/Qt6XmlPrivate
%dir %{_qt6_libdir}/cmake/Qt6EglFSDeviceIntegrationPrivate
%dir %{_qt6_libdir}/cmake/Qt6EglFsKmsGbmSupportPrivate
%dir %{_qt6_libdir}/cmake/Qt6EglFsKmsSupportPrivate
%dir %{_qt6_libdir}/cmake/Qt6XcbQpaPrivate
%{_qt6_libdir}/cmake/Qt6CorePrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6DBusPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6GuiPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6NetworkPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6OpenGLPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6PrintSupportPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6SqlPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6TestInternalsPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6TestInternalsPrivate/3rdparty/cmake/*.cmake
%{_qt6_libdir}/cmake/Qt6TestPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6WidgetsPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6XmlPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6EglFSDeviceIntegrationPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6EglFsKmsGbmSupportPrivate/*.cmake
%{_qt6_libdir}/cmake/Qt6EglFsKmsSupportPrivate/*.cmake
@ -783,11 +829,14 @@ make check -k ||:
%{_qt6_descriptionsdir}/EglFsKmsGbmSupportPrivate.json
%{_qt6_descriptionsdir}/EglFsKmsSupportPrivate.json
%{_qt6_descriptionsdir}/XcbQpaPrivate.json
%{_qt6_metatypesdir}/qt6eglfsdeviceintegrationprivate_*_metatypes.json
%{_qt6_metatypesdir}/qt6eglfskmsgbmsupportprivate_*_metatypes.json
%{_qt6_metatypesdir}/qt6eglfskmssupportprivate_*_metatypes.json
%{_qt6_metatypesdir}/qt6xcbqpaprivate_*_metatypes.json
%{_qt6_metatypesdir}/qt6eglfsdeviceintegrationprivate_metatypes.json
%{_qt6_metatypesdir}/qt6eglfskmsgbmsupportprivate_metatypes.json
%{_qt6_metatypesdir}/qt6eglfskmssupportprivate_metatypes.json
%{_qt6_metatypesdir}/qt6xcbqpaprivate_metatypes.json
%{_qt6_metatypesdir}/qt6waylandclient_metatypes.json
%{_qt6_metatypesdir}/qt6wlshellintegrationprivate_metatypes.json
%{_qt6_headerdir}/*/%{qt_version}/
%{_qt6_descriptionsdir}/TestInternalsPrivate.json
%files static
%dir %{_qt6_libdir}/cmake/Qt6ExampleIconsPrivate
@ -798,35 +847,35 @@ make check -k ||:
%{_qt6_descriptionsdir}/ExampleIconsPrivate.json
%dir %{_qt6_archdatadir}/objects-*
%{_qt6_archdatadir}/objects-*/ExampleIconsPrivate_resources_1/
%{_qt6_metatypesdir}/qt6exampleiconsprivate_*_metatypes.json
%{_qt6_metatypesdir}/qt6exampleiconsprivate_metatypes.json
%dir %{_qt6_libdir}/cmake/Qt6DeviceDiscoverySupportPrivate
%{_qt6_libdir}/cmake/Qt6DeviceDiscoverySupportPrivate/*.cmake
%{_qt6_headerdir}/QtDeviceDiscoverySupport
%{_qt6_libdir}/libQt6DeviceDiscoverySupport.*a
%{_qt6_libdir}/libQt6DeviceDiscoverySupport.prl
%{_qt6_descriptionsdir}/DeviceDiscoverySupportPrivate.json
%{_qt6_metatypesdir}/qt6devicediscoverysupportprivate_*_metatypes.json
%{_qt6_metatypesdir}/qt6devicediscoverysupportprivate_metatypes.json
%dir %{_qt6_libdir}/cmake/Qt6FbSupportPrivate
%{_qt6_libdir}/cmake/Qt6FbSupportPrivate/*.cmake
%{_qt6_headerdir}/QtFbSupport
%{_qt6_libdir}/libQt6FbSupport.*a
%{_qt6_libdir}/libQt6FbSupport.prl
%{_qt6_descriptionsdir}/FbSupportPrivate.json
%{_qt6_metatypesdir}/qt6fbsupportprivate_*_metatypes.json
%{_qt6_metatypesdir}/qt6fbsupportprivate_metatypes.json
%dir %{_qt6_libdir}/cmake/Qt6InputSupportPrivate
%{_qt6_libdir}/cmake/Qt6InputSupportPrivate/*.cmake
%{_qt6_headerdir}/QtInputSupport
%{_qt6_libdir}/libQt6InputSupport.*a
%{_qt6_libdir}/libQt6InputSupport.prl
%{_qt6_descriptionsdir}/InputSupportPrivate.json
%{_qt6_metatypesdir}/qt6inputsupportprivate_*_metatypes.json
%{_qt6_metatypesdir}/qt6inputsupportprivate_metatypes.json
%dir %{_qt6_libdir}/cmake/Qt6KmsSupportPrivate
%{_qt6_libdir}/cmake/Qt6KmsSupportPrivate/*.cmake
%{_qt6_headerdir}/QtKmsSupport
%{_qt6_libdir}/libQt6KmsSupport.*a
%{_qt6_libdir}/libQt6KmsSupport.prl
%{_qt6_descriptionsdir}/KmsSupportPrivate.json
%{_qt6_metatypesdir}/qt6kmssupportprivate_*_metatypes.json
%{_qt6_metatypesdir}/qt6kmssupportprivate_metatypes.json
%if 0%{?examples}
%files examples
@ -861,6 +910,8 @@ make check -k ||:
%{_qt6_libdir}/libQt6OpenGL.so.6*
%{_qt6_libdir}/libQt6OpenGLWidgets.so.6*
%{_qt6_libdir}/libQt6PrintSupport.so.6*
%{_qt6_libdir}/libQt6WaylandClient.so.6*
%{_qt6_libdir}/libQt6WlShellIntegration.so.6*
%{_qt6_libdir}/libQt6Widgets.so.6*
%{_qt6_libdir}/libQt6XcbQpa.so.6*
# Generic
@ -899,17 +950,71 @@ make check -k ||:
%{_qt6_plugindir}/platforms/libqlinuxfb.so
%{_qt6_plugindir}/platforms/libqminimal.so
%{_qt6_plugindir}/platforms/libqoffscreen.so
%{_qt6_plugindir}/platforms/libqxcb.so
%{_qt6_plugindir}/platforms/libqvnc.so
%{_qt6_plugindir}/platforms/libqvkkhrdisplay.so
%{_qt6_plugindir}/platforms/libqwayland.so
%{_qt6_plugindir}/platforms/libqxcb.so
%{_qt6_plugindir}/xcbglintegrations/libqxcb-glx-integration.so
%{_qt6_plugindir}/printsupport/libcupsprintersupport.so
# Platformthemes
%{_qt6_plugindir}/platformthemes/libqxdgdesktopportal.so
%{_qt6_plugindir}/platformthemes/libqgtk3.so
# Wayland plugins and protocols
%{_qt6_plugindir}/wayland-decoration-client/
%{_qt6_plugindir}/wayland-graphics-integration-client
%{_qt6_plugindir}/wayland-shell-integration
%{_qt6_datadir}/wayland/extensions/
%{_qt6_datadir}/wayland/protocols/
%changelog
* Mon Dec 22 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.1-3
- Fix crash in QWaylandShmBackingStore::scroll()
* Mon Dec 08 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.1-2
- Re-add wayland fixes for mouse scrolling
* Thu Nov 20 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.1-1
- 6.10.1
* Mon Nov 10 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.0-3
- Backport wayland fixes for mouse scrolling
* Wed Oct 29 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.0-2
- Backport: Wayland - convey preference for server side decorations
* Tue Oct 07 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.0-1
- 6.10.0
* Tue Sep 30 2025 Gwyn Ciesla <gwync@protonmail.com> - 6.10.0~rc-2
- Firebird 5 rebuild
* Thu Sep 25 2025 Jan Grulich <jgrulich@redhat.com> - 6.10.0~rc-1
- 6.10.0 RC
* Thu Aug 28 2025 Jan Grulich <jgrulich@redhat.com> - 6.9.2-1
- 6.9.2
* Tue Aug 05 2025 František Zatloukal <fzatlouk@redhat.com> - 6.9.1-4
- Rebuilt for icu 77.1
* Mon Jul 28 2025 Adam Williamson <awilliam@redhat.com> - 6.9.1-3
- Adjust for https://fedoraproject.org/wiki/Changes/dropingOfCertPemFile removals
* Fri Jul 25 2025 Fedora Release Engineering <releng@fedoraproject.org> - 6.9.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild
* Mon Jun 02 2025 Jan Grulich <jgrulich@redhat.com> - 6.9.1-1
- 6.9.1
* Mon Apr 28 2025 Jan Grulich <jgrulich@redhat.com> - 6.9.0-2
- Fix possible crash in FontConfig database
* Wed Apr 02 2025 Jan Grulich <jgrulich@redhat.com> - 6.9.0-1
- 6.9.0
* Fri Mar 21 2025 Jan Grulich <jgrulich@redhat.com> - 6.9.0-1
- 6.9.0 RC
* Thu Feb 13 2025 Jan Grulich <jgrulich@redhat.com> - 6.8.2-3
- Fix rendering of combined emojis
@ -1094,7 +1199,7 @@ make check -k ||:
* Fri Apr 7 2023 Marie Loise Nolden <loise@kde.org> - 6.5.0-2
- fix xcb plugin with new dependency xcb-cursor instead of Xcursor
introduction with qt 6.5, add firebird sql plugin cleanly, clean up spec file
* Mon Apr 03 2023 Jan Grulich <jgrulich@redhat.com> - 6.5.0-1
- 6.5.0

View file

@ -1,85 +0,0 @@
diff --git a/src/gui/text/unix/qfontconfigdatabase.cpp b/src/gui/text/unix/qfontconfigdatabase.cpp
index 474644b8..f61e6e83 100644
--- a/src/gui/text/unix/qfontconfigdatabase.cpp
+++ b/src/gui/text/unix/qfontconfigdatabase.cpp
@@ -592,6 +592,7 @@ void QFontconfigDatabase::populateFontDatabase()
++f;
}
+ cacheEmojiFontFamily();
//QPA has very lazy population of the font db. We want it to be initialized when
//QApplication is constructed, so that the population procedure can do something like this to
//set the default font
@@ -735,6 +736,9 @@ QStringList QFontconfigDatabase::fallbacksForFamily(const QString &family, QFont
if (!pattern)
return fallbackFamilies;
+ if (!m_cacheEmojiFontFamily.isEmpty())
+ fallbackFamilies << m_cacheEmojiFontFamily;
+
FcValue value;
value.type = FcTypeString;
const QByteArray cs = family.toUtf8();
@@ -1016,4 +1020,47 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef
engine->glyphFormat = format;
}
+void QFontconfigDatabase::cacheEmojiFontFamily()
+{
+ FcPattern *pattern;
+ pattern = FcPatternCreate();
+
+ FcValue value;
+ value.type = FcTypeString;
+ value.u.s = (const FcChar8 *)"emoji";
+ FcPatternAdd(pattern,FC_FAMILY,value,true);
+
+ FcLangSet *ls = FcLangSetCreate();
+ FcLangSetAdd(ls, (const FcChar8*)"und-zsye");
+ FcPatternAddLangSet(pattern, FC_LANG, ls);
+
+ FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+
+ FcResult result = FcResultMatch;
+ FcFontSet *fontSet = FcFontSort(nullptr,pattern,FcTrue,nullptr,&result);
+ FcPatternDestroy(pattern);
+
+ if (fontSet) {
+ for (int i = 0; i < fontSet->nfont; i++) {
+ FcChar8 *value = nullptr;
+ if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
+ continue;
+
+ FcLangSet *rls = nullptr;
+ if (FcPatternGetLangSet(fontSet->fonts[i], FC_LANG, 0, &rls) != FcResultMatch)
+ continue;
+
+ if (!FcLangSetContains(rls, ls))
+ continue;
+
+ m_cacheEmojiFontFamily = QString::fromUtf8((const char *)value);
+ break;
+ }
+ FcFontSetDestroy(fontSet);
+ }
+
+ FcLangSetDestroy(ls);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/text/unix/qfontconfigdatabase_p.h b/src/gui/text/unix/qfontconfigdatabase_p.h
index cf15306e..90b94087 100644
--- a/src/gui/text/unix/qfontconfigdatabase_p.h
+++ b/src/gui/text/unix/qfontconfigdatabase_p.h
@@ -37,7 +37,10 @@ public:
QFont defaultFont() const override;
private:
+ void cacheEmojiFontFamily();
void setupFontEngine(QFontEngineFT *engine, const QFontDef &fontDef) const;
+
+ QString m_cacheEmojiFontFamily;
};
QT_END_NAMESPACE

File diff suppressed because it is too large Load diff

View file

@ -1,96 +0,0 @@
From 486bbc7a5bc4483ecc2a6b8927543725e3d38722 Mon Sep 17 00:00:00 2001
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Date: Tue, 26 Nov 2024 14:39:44 +0100
Subject: Fix regression when looking up fallback fonts
This amends 16850709306589a2433c0038605d365a6b6bedad.
In that change, the final pass for looking up fallback
fonts was turned into a lambda so that we could run it
an additional time at the very end. However, when making
a lambda from the code, some of the logic was accidentally
changed.
Specifically, for multi engines the original code would pass
Script_Common instead of the requested script to the match()
function, but it would still pass the actual script to
loadEngine() as well as store it in the key. In the changed
code, Script_Common would be used for all of these when multi
was true.
This change was not intentional and it caused us to fail to
load certain fallback fonts, for instance the Bengali font
on Windows.
Fixes: QTBUG-131632
Change-Id: Id215ee4dc2851e846be27a3a25a31cad57b8f67d
Reviewed-by: Lars Knoll <lars@knoll.priv.no>
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 96c2337e..0c2a4b66 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -2734,17 +2734,23 @@ QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &req,
if (script > QChar::Script_Common)
fallbacks += QString(); // Find the first font matching the specified script.
- auto findMatchingFallback = [&](int xscript) {
+ auto findMatchingFallback = [&fallbacks,
+ &index,
+ &multi,
+ &fontCache,
+ &blackListed,
+ &request](int lookupScript, int cacheScript) {
+ QFontEngine *engine = nullptr;
for (int i = 0; !engine && i < fallbacks.size(); i++) {
QFontDef def = request;
def.families = QStringList(fallbacks.at(i));
- QFontCache::Key key(def, xscript, multi ? 1 : 0);
+ QFontCache::Key key(def, cacheScript, multi ? 1 : 0);
engine = fontCache->findEngine(key);
if (!engine) {
QtFontDesc desc;
do {
- index = match(xscript,
+ index = match(lookupScript,
def,
def.families.constFirst(),
""_L1,
@@ -2755,7 +2761,12 @@ QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &req,
QFontDef loadDef = def;
if (loadDef.families.isEmpty())
loadDef.families = QStringList(desc.family->name);
- engine = loadEngine(xscript, loadDef, desc.family, desc.foundry, desc.style, desc.size);
+ engine = loadEngine(cacheScript,
+ loadDef,
+ desc.family,
+ desc.foundry,
+ desc.style,
+ desc.size);
if (engine)
initFontDef(desc, loadDef, &engine->fontDef, multi);
else
@@ -2764,15 +2775,20 @@ QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &req,
} while (index >= 0 && !engine);
}
}
+
+ return engine;
};
- findMatchingFallback(multi && script != QFontDatabasePrivate::Script_Emoji ? QChar::Script_Common: script);
+ engine = findMatchingFallback(multi && script != QFontDatabasePrivate::Script_Emoji
+ ? QChar::Script_Common
+ : script,
+ script);
// If we are looking for a color font and there are no color fonts on the system,
// we will end up here, for one final pass. This is a rare occurrence so we accept
// and extra pass on the fallbacks for this.
if (!engine && script == QFontDatabasePrivate::Script_Emoji)
- findMatchingFallback(QChar::Script_Common);
+ engine = findMatchingFallback(QChar::Script_Common, script);
}
if (!engine)

View file

@ -1,34 +0,0 @@
From 83864f8682da73a062a3ca32b928377dfc333021 Mon Sep 17 00:00:00 2001
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Date: Wed, 15 Jan 2025 14:52:55 +0100
Subject: [PATCH] FontConfig: Don't register hardcoded fonts as color fonts
This amends 16850709306589a2433c0038605d365a6b6bedad. The patch
aimed to pass false for the color font parameter, but got it in
the wrong position, so it passed false for the pixel size instead.
The registerFont() function is a real mess, and it should be cleaned
up, but this at least fixes the immediate bug.
Pick-to: 6.9
Task-number: QTBUG-132821
Change-Id: Id54989960aa5f86d3c79423d004530bb6a4fa475
---
diff --git a/src/gui/text/unix/qfontconfigdatabase.cpp b/src/gui/text/unix/qfontconfigdatabase.cpp
index 7866e341..790316a6 100644
--- a/src/gui/text/unix/qfontconfigdatabase.cpp
+++ b/src/gui/text/unix/qfontconfigdatabase.cpp
@@ -622,9 +622,9 @@ void QFontconfigDatabase::populateFontDatabase()
while (f->qtname) {
QString familyQtName = QString::fromLatin1(f->qtname);
- registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,false,0,f->fixed,ws,nullptr);
- registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,false,0,f->fixed,ws,nullptr);
- registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,false,0,f->fixed,ws,nullptr);
+ registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,f->fixed,false,ws,nullptr);
+ registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,f->fixed,false,ws,nullptr);
+ registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,f->fixed,false,ws,nullptr);
++f;
}

View file

@ -1,43 +0,0 @@
From 2c309f71705449607592bb4588bcc56223da897b Mon Sep 17 00:00:00 2001
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Date: Wed, 15 Jan 2025 15:39:16 +0100
Subject: [PATCH] FontConfig: Fix detection of color fonts
There were two mistakes in the code that intended to detect
if a specific font was a color font in the FontConfig database.
1. The "int n" parameter in FcPatternGet*() is not an array size,
but an index, so it should be 0 and not 1.
2. We need to add FC_COLOR to the list of properties in our pattern
when populating the database, otherwise we will just fail to match
it and none of the system fonts will be listed as color.
Pick-to: 6.9
Fixes: QTBUG-132377
Change-Id: Ib3c112e8a354abacd05679c62283a1f1abfb40ee
---
diff --git a/src/gui/text/unix/qfontconfigdatabase.cpp b/src/gui/text/unix/qfontconfigdatabase.cpp
index de6618f..20794ed 100644
--- a/src/gui/text/unix/qfontconfigdatabase.cpp
+++ b/src/gui/text/unix/qfontconfigdatabase.cpp
@@ -478,7 +478,7 @@
FcBool colorFont = false;
#ifdef FC_COLOR
- FcPatternGetBool(pattern, FC_COLOR, 1, &colorFont);
+ FcPatternGetBool(pattern, FC_COLOR, 0, &colorFont);
#endif
// Note: stretch should really be an int but registerFont incorrectly uses an enum
@@ -577,6 +577,9 @@
#if FC_VERSION >= 20297
FC_CAPABILITY,
#endif
+#if defined(FC_COLOR)
+ FC_COLOR,
+#endif
(const char *)nullptr
};
const char **p = properties;

View file

@ -1,568 +0,0 @@
From aa7d479be0df3e118580e87f30e061445dfb37e3 Mon Sep 17 00:00:00 2001
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Date: Fri, 2 Feb 2024 15:45:20 +0100
Subject: Introduce emoji-segmenter to 3rdparty code
This is a parser for emoji sequences developed by Google
which is used in multiple other projects for parsing
sequences of characters to see if they should be represented
as color emojis or as monochrome text.
[ChangeLog][Third-Party Code] Added the emoji-segmenter to
third party code, for supporting complex emoji sequences.
This can be configured using the -emojisegmenter option.
Task-number: QTBUG-111801
Change-Id: I7f87b0751415024d29f074d133850027f0003e29
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
diff --git a/config_help.txt b/config_help.txt
index deb38c9c2f..09aebf2e65 100644
--- a/config_help.txt
+++ b/config_help.txt
@@ -298,6 +298,7 @@ Gui, printing, widget options:
-cups ................ Enable CUPS support [auto] (Unix only)
+ -emojisegmenter ...... Enable complex emoji sequences [yes]
-fontconfig .......... Enable Fontconfig support [auto] (Unix only)
-freetype ............ Select used FreeType [system/qt/no]
-harfbuzz ............ Select used HarfBuzz-NG [system/qt/no]
diff --git a/src/3rdparty/emoji-segmenter/CONTRIBUTING.md b/src/3rdparty/emoji-segmenter/CONTRIBUTING.md
new file mode 100644
index 0000000000..db177d4ac7
--- /dev/null
+++ b/src/3rdparty/emoji-segmenter/CONTRIBUTING.md
@@ -0,0 +1,28 @@
+# How to Contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution;
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to <https://cla.developers.google.com/> to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult
+[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
+information on using pull requests.
+
+## Community Guidelines
+
+This project follows
+[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/).
diff --git a/src/3rdparty/emoji-segmenter/NEWS b/src/3rdparty/emoji-segmenter/NEWS
new file mode 100644
index 0000000000..3fd07f1ce2
--- /dev/null
+++ b/src/3rdparty/emoji-segmenter/NEWS
@@ -0,0 +1,28 @@
+Overview of changes leading to 0.4.0
+Friday, November 15, 2024
+====================================
+
+* Add `make size` targe to
+ determine binary size.
+* Set has_vs for
+ emoji_keycap_sequence
+
+Overview of changes leading to 0.3.0
+Tuesday, September 5, 2024
+====================================
+
+* Add segmentation for variation
+ selector pairs, VS15 and VS16,
+ needed for font-variant-emoji.
+
+Overview of changes leading to 0.2.0
+Tuesday, Februar 20, 2024
+====================================
+
+* Change Ragel mode to -F1
+
+Overview of changes leading to 0.1.0
+Tuesday, January 29, 2019
+====================================
+
+* Initial release
diff --git a/src/3rdparty/emoji-segmenter/README.md b/src/3rdparty/emoji-segmenter/README.md
new file mode 100644
index 0000000000..571a1a4515
--- /dev/null
+++ b/src/3rdparty/emoji-segmenter/README.md
@@ -0,0 +1,103 @@
+Emoji Segmenter
+===
+
+This repository contains a Ragel grammar and generated C code for segmenting
+runs of text into text-presentation and emoji-presentation runs. It is currently
+used in projects such as Chromium and Pango for deciding which preferred
+presentation, color or text, a run of text should have.
+
+The goal is to stay very close to the grammar definitions in [Unicode Technical
+Standard #51](http://www.unicode.org/reports/tr51/).
+
+API
+===
+
+By including the `emoji_presentation_scanner.c` file, you will be able to call
+the following API
+
+```
+scan_emoji_presentation (emoji_text_iter_t p,
+ const emoji_text_iter_t pe,
+ bool* is_emoji,
+ bool* has_vs)
+```
+
+This API call will scan `emoji_text_iter_t p` for the next grammar-token and
+return an iterator that points to the end of the next token. An end iterator
+needs be specified as `pe` so that the scanner can compare against this and
+knows where to stop. In the reference parameter `is_emoji` it returns whether
+this token has emoji-presentation text-presentation, `has_vs` is set to true
+if the token contains a variation selector.
+
+A grammar token is either a combination of an emoji plus variation selector 15
+for text presentation, an emoji presentation sequence (emoji + VS16), an emoji
+presentation emoji or emoji sequence, or a single text presentation character.
+
+`emoji_text_iter_t` is an iterator type over a buffer of the character classes
+that are defined at the beginning of the the Ragel file, e.g. `EMOJI`,
+`EMOJI_TEXT_PRESENTATION`, `REGIONAL_INDICATOR`, `KEYCAP_BASE`, etc.
+
+By typedef'ing `emoji_text_iter_t` to your own iterator type, you can implement
+an adapter class that iterates over an input text buffer in any encoding, and on
+dereferencing returns the correct Ragel class by implementing something similar
+to the following Unicode character class to Ragel class mapping, example taken
+from Chromium:
+
+```
+char EmojiSegmentationCategory(UChar32 codepoint) {
+ // Specific ones first.
+ if (codepoint == kCombiningEnclosingKeycapCharacter)
+ return COMBINING_ENCLOSING_KEYCAP;
+ if (codepoint == kCombiningEnclosingCircleBackslashCharacter)
+ return COMBINING_ENCLOSING_CIRCLE_BACKSLASH;
+ if (codepoint == kZeroWidthJoinerCharacter)
+ return ZWJ;
+ if (codepoint == kVariationSelector15Character)
+ return VS15;
+ if (codepoint == kVariationSelector16Character)
+ return VS16;
+ if (codepoint == 0x1F3F4)
+ return TAG_BASE;
+ if ((codepoint >= 0xE0030 && codepoint <= 0xE0039) ||
+ (codepoint >= 0xE0061 && codepoint <= 0xE007A))
+ return TAG_SEQUENCE;
+ if (codepoint == 0xE007F)
+ return TAG_TERM;
+ if (Character::IsEmojiModifierBase(codepoint))
+ return EMOJI_MODIFIER_BASE;
+ if (Character::IsModifier(codepoint))
+ return EMOJI_MODIFIER;
+ if (Character::IsRegionalIndicator(codepoint))
+ return REGIONAL_INDICATOR;
+ if (Character::IsEmojiKeycapBase(codepoint))
+ return KEYCAP_BASE;
+
+ if (Character::IsEmojiEmojiDefault(codepoint))
+ return EMOJI_EMOJI_PRESENTATION;
+ if (Character::IsEmojiTextDefault(codepoint))
+ return EMOJI_TEXT_PRESENTATION;
+ if (Character::IsEmoji(codepoint))
+ return EMOJI;
+
+ // Ragel state machine will interpret unknown category as "any".
+ return kMaxEmojiScannerCategory;
+}
+```
+
+Update/Build requisites
+===
+
+You need to have ragel installed if you want to modify the grammar and generate a new C file as output.
+
+`apt-get install ragel`
+
+then run
+
+`make`
+
+to update the `emoji_presentation_scanner.c` and `emoji_presentation_scanner_vs.c` output C source file.
+
+Contributing
+===
+
+See the CONTRIBUTING.md file for how to contribute.
diff --git a/src/3rdparty/emoji-segmenter/REUSE.toml b/src/3rdparty/emoji-segmenter/REUSE.toml
new file mode 100644
index 0000000000..53d2dc47c7
--- /dev/null
+++ b/src/3rdparty/emoji-segmenter/REUSE.toml
@@ -0,0 +1,7 @@
+version = 1
+
+[[annotations]]
+path = ["**"]
+precedence = "closest"
+SPDX-FileCopyrightText = "Copyright 2019 Google LLC"
+SPDX-License-Identifier = "Apache-2.0"
diff --git a/src/3rdparty/emoji-segmenter/emoji_presentation_scanner.c b/src/3rdparty/emoji-segmenter/emoji_presentation_scanner.c
new file mode 100644
index 0000000000..00b7700a9a
--- /dev/null
+++ b/src/3rdparty/emoji-segmenter/emoji_presentation_scanner.c
@@ -0,0 +1,251 @@
+
+#line 1 "emoji_presentation_scanner.rl"
+/* Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdbool.h>
+
+#ifndef EMOJI_LINKAGE
+#define EMOJI_LINKAGE static
+#endif
+
+
+#line 23 "emoji_presentation_scanner.c"
+static const unsigned char _emoji_presentation_trans_keys[] = {
+ 0u, 13u, 14u, 15u, 0u, 13u, 9u, 12u, 10u, 12u, 10u, 10u, 4u, 12u, 4u, 12u,
+ 6u, 6u, 9u, 12u, 8u, 8u, 8u, 10u, 9u, 14u, 0
+};
+
+static const char _emoji_presentation_key_spans[] = {
+ 14, 2, 14, 4, 3, 1, 9, 9,
+ 1, 4, 1, 3, 6
+};
+
+static const char _emoji_presentation_index_offsets[] = {
+ 0, 15, 18, 33, 38, 42, 44, 54,
+ 64, 66, 71, 73, 77
+};
+
+static const char _emoji_presentation_indicies[] = {
+ 1, 1, 1, 2, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 1, 0, 4,
+ 5, 3, 6, 6, 7, 8, 9, 9,
+ 10, 11, 9, 9, 9, 9, 9, 12,
+ 9, 5, 13, 14, 15, 0, 13, 16,
+ 17, 16, 13, 0, 17, 16, 16, 16,
+ 16, 16, 13, 16, 17, 16, 17, 16,
+ 16, 16, 16, 5, 13, 14, 15, 16,
+ 5, 18, 5, 13, 19, 20, 18, 14,
+ 21, 23, 22, 13, 22, 5, 13, 14,
+ 15, 16, 4, 16, 0
+};
+
+static const char _emoji_presentation_trans_targs[] = {
+ 2, 4, 6, 2, 1, 2, 3, 3,
+ 7, 2, 8, 9, 12, 0, 2, 5,
+ 2, 5, 2, 10, 11, 2, 2, 2
+};
+
+static const char _emoji_presentation_trans_actions[] = {
+ 1, 2, 2, 3, 0, 4, 7, 2,
+ 2, 8, 0, 7, 2, 0, 9, 10,
+ 11, 2, 12, 0, 10, 13, 14, 15
+};
+
+static const char _emoji_presentation_to_state_actions[] = {
+ 0, 0, 5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+};
+
+static const char _emoji_presentation_from_state_actions[] = {
+ 0, 0, 6, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+};
+
+static const char _emoji_presentation_eof_trans[] = {
+ 1, 4, 0, 1, 17, 1, 17, 17,
+ 19, 19, 22, 23, 17
+};
+
+static const int emoji_presentation_start = 2;
+
+static const int emoji_presentation_en_text_and_emoji_run = 2;
+
+
+#line 26 "emoji_presentation_scanner.rl"
+
+
+
+#line 100 "emoji_presentation_scanner.rl"
+
+
+EMOJI_LINKAGE emoji_text_iter_t
+scan_emoji_presentation (emoji_text_iter_t p,
+ const emoji_text_iter_t pe,
+ bool* is_emoji,
+ bool* has_vs)
+{
+ emoji_text_iter_t ts;
+ emoji_text_iter_t te;
+ const emoji_text_iter_t eof = pe;
+
+ (void)ts;
+
+ unsigned act;
+ int cs;
+
+
+#line 100 "emoji_presentation_scanner.c"
+ {
+ cs = emoji_presentation_start;
+ ts = 0;
+ te = 0;
+ act = 0;
+ }
+
+#line 106 "emoji_presentation_scanner.c"
+ {
+ int _slen;
+ int _trans;
+ const unsigned char *_keys;
+ const char *_inds;
+ if ( p == pe )
+ goto _test_eof;
+_resume:
+ switch ( _emoji_presentation_from_state_actions[cs] ) {
+ case 6:
+#line 1 "NONE"
+ {ts = p;}
+ break;
+#line 118 "emoji_presentation_scanner.c"
+ }
+
+ _keys = _emoji_presentation_trans_keys + (cs<<1);
+ _inds = _emoji_presentation_indicies + _emoji_presentation_index_offsets[cs];
+
+ _slen = _emoji_presentation_key_spans[cs];
+ _trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
+ (*p) <= _keys[1] ?
+ (*p) - _keys[0] : _slen ];
+
+_eof_trans:
+ cs = _emoji_presentation_trans_targs[_trans];
+
+ if ( _emoji_presentation_trans_actions[_trans] == 0 )
+ goto _again;
+
+ switch ( _emoji_presentation_trans_actions[_trans] ) {
+ case 9:
+#line 94 "emoji_presentation_scanner.rl"
+ {te = p+1;{ *is_emoji = false; *has_vs = true; return te; }}
+ break;
+ case 15:
+#line 95 "emoji_presentation_scanner.rl"
+ {te = p+1;{ *is_emoji = true; *has_vs = true; return te; }}
+ break;
+ case 4:
+#line 96 "emoji_presentation_scanner.rl"
+ {te = p+1;{ *is_emoji = true; *has_vs = false; return te; }}
+ break;
+ case 8:
+#line 97 "emoji_presentation_scanner.rl"
+ {te = p+1;{ *is_emoji = false; *has_vs = false; return te; }}
+ break;
+ case 13:
+#line 94 "emoji_presentation_scanner.rl"
+ {te = p;p--;{ *is_emoji = false; *has_vs = true; return te; }}
+ break;
+ case 14:
+#line 95 "emoji_presentation_scanner.rl"
+ {te = p;p--;{ *is_emoji = true; *has_vs = true; return te; }}
+ break;
+ case 11:
+#line 96 "emoji_presentation_scanner.rl"
+ {te = p;p--;{ *is_emoji = true; *has_vs = false; return te; }}
+ break;
+ case 12:
+#line 97 "emoji_presentation_scanner.rl"
+ {te = p;p--;{ *is_emoji = false; *has_vs = false; return te; }}
+ break;
+ case 3:
+#line 96 "emoji_presentation_scanner.rl"
+ {{p = ((te))-1;}{ *is_emoji = true; *has_vs = false; return te; }}
+ break;
+ case 1:
+#line 1 "NONE"
+ { switch( act ) {
+ case 2:
+ {{p = ((te))-1;} *is_emoji = true; *has_vs = true; return te; }
+ break;
+ case 3:
+ {{p = ((te))-1;} *is_emoji = true; *has_vs = false; return te; }
+ break;
+ case 4:
+ {{p = ((te))-1;} *is_emoji = false; *has_vs = false; return te; }
+ break;
+ }
+ }
+ break;
+ case 10:
+#line 1 "NONE"
+ {te = p+1;}
+#line 95 "emoji_presentation_scanner.rl"
+ {act = 2;}
+ break;
+ case 2:
+#line 1 "NONE"
+ {te = p+1;}
+#line 96 "emoji_presentation_scanner.rl"
+ {act = 3;}
+ break;
+ case 7:
+#line 1 "NONE"
+ {te = p+1;}
+#line 97 "emoji_presentation_scanner.rl"
+ {act = 4;}
+ break;
+#line 188 "emoji_presentation_scanner.c"
+ }
+
+_again:
+ switch ( _emoji_presentation_to_state_actions[cs] ) {
+ case 5:
+#line 1 "NONE"
+ {ts = 0;}
+ break;
+#line 195 "emoji_presentation_scanner.c"
+ }
+
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ if ( _emoji_presentation_eof_trans[cs] > 0 ) {
+ _trans = _emoji_presentation_eof_trans[cs] - 1;
+ goto _eof_trans;
+ }
+ }
+
+ }
+
+#line 118 "emoji_presentation_scanner.rl"
+
+
+ /* Should not be reached. */
+ *is_emoji = false;
+ *has_vs = false;
+ return p;
+}
diff --git a/src/3rdparty/emoji-segmenter/patch/0001-Compile-with-warnings-are-errors.patch b/src/3rdparty/emoji-segmenter/patch/0001-Compile-with-warnings-are-errors.patch
new file mode 100644
index 0000000000..0cc1868ca7
--- /dev/null
+++ b/src/3rdparty/emoji-segmenter/patch/0001-Compile-with-warnings-are-errors.patch
@@ -0,0 +1,26 @@
+From 4ced1426e27320e00b0dd28693df5d95c648d230 Mon Sep 17 00:00:00 2001
+From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
+Date: Thu, 14 Nov 2024 09:42:11 +0100
+Subject: [PATCH] Compile with warnings-are-errors
+
+Change-Id: Icea8febefc90f3f047143e5b76ff511145c0dcae
+---
+ src/3rdparty/emoji-segmenter/emoji_presentation_scanner.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/3rdparty/emoji-segmenter/emoji_presentation_scanner.c b/src/3rdparty/emoji-segmenter/emoji_presentation_scanner.c
+index 56e2e78033..ce7e01846c 100644
+--- a/src/3rdparty/emoji-segmenter/emoji_presentation_scanner.c
++++ b/src/3rdparty/emoji-segmenter/emoji_presentation_scanner.c
+@@ -101,6 +101,8 @@ scan_emoji_presentation (emoji_text_iter_t p,
+ emoji_text_iter_t te;
+ const emoji_text_iter_t eof = pe;
+
++ (void)ts;
++
+ unsigned act;
+ int cs;
+
+--
+2.40.0.windows.1
+
diff --git a/src/3rdparty/emoji-segmenter/qt_attribution.json b/src/3rdparty/emoji-segmenter/qt_attribution.json
new file mode 100644
index 0000000000..64083381d4
--- /dev/null
+++ b/src/3rdparty/emoji-segmenter/qt_attribution.json
@@ -0,0 +1,16 @@
+{
+ "Id": "emoji-segmenter",
+ "Name": "Emoji Segmenter",
+ "QDocModule": "qtgui",
+ "QtUsage": "Used in QtGui for parsing complex emoji sequences. Can be configured using the -emojisegmenter option.",
+ "SecurityCritical": true,
+
+ "Description": "A parser for emoji sequences.",
+ "Homepage": "https://github.com/google/emoji-segmenter",
+ "Version": "0.4.0",
+ "DownloadLocation": "https://github.com/google/emoji-segmenter/releases/tag/0.4.0",
+
+ "License": "Apache License 2.0",
+ "LicenseId": "Apache-2.0",
+ "Copyright": "Copyright 2019 Google LLC"
+}
diff --git a/src/gui/configure.cmake b/src/gui/configure.cmake
index b7c1e8e00c..7889445976 100644
--- a/src/gui/configure.cmake
+++ b/src/gui/configure.cmake
@@ -699,6 +699,12 @@ qt_feature("direct2d1_1" PRIVATE
LABEL "Direct 2D 1.1"
CONDITION QT_FEATURE_direct2d AND TEST_d2d1_1
)
+qt_feature("emojisegmenter" PUBLIC PRIVATE
+ SECTION "Fonts"
+ LABEL "Emoji Segmenter"
+ PURPOSE "Supports parsing complex emoji sequences for better font resolution."
+)
+qt_feature_definition("emojisegmenter" "QT_NO_EMOJISEGMENTER" NEGATE VALUE "1")
qt_feature("evdev" PRIVATE
LABEL "evdev"
CONDITION QT_FEATURE_thread AND TEST_evdev
@@ -1299,6 +1305,7 @@ qt_feature("wayland" PUBLIC
qt_configure_add_summary_section(NAME "Qt Gui")
qt_configure_add_summary_entry(ARGS "accessibility")
+qt_configure_add_summary_entry(ARGS "emojisegmenter")
qt_configure_add_summary_entry(ARGS "freetype")
qt_configure_add_summary_entry(ARGS "system-freetype")
qt_configure_add_summary_entry(ARGS "harfbuzz")
diff --git a/src/gui/qt_cmdline.cmake b/src/gui/qt_cmdline.cmake
index 446618ebc4..5465b2c63e 100644
--- a/src/gui/qt_cmdline.cmake
+++ b/src/gui/qt_cmdline.cmake
@@ -10,6 +10,7 @@ qt_commandline_option(eglfs TYPE boolean)
qt_commandline_option(evdev TYPE boolean)
qt_commandline_option(fontconfig TYPE boolean)
qt_commandline_option(freetype TYPE enum VALUES no qt system)
+qt_commandline_option(emojisegmenter TYPE boolean)
qt_commandline_option(gbm TYPE boolean)
qt_commandline_option(gif TYPE boolean)
qt_commandline_option(harfbuzz TYPE enum VALUES no qt system)

View file

@ -1,50 +0,0 @@
From a43c7e58046604796aa69974ea1c5d3e2648c755 Mon Sep 17 00:00:00 2001
From: Thiago Macieira <thiago.macieira@intel.com>
Date: Fri, 24 Jan 2025 11:07:58 -0800
Subject: [PATCH] QLibraryInfo: speed up checking if ":/qt/etc/qt.conf"
resource exists
Go straight for QResource, because this is run very early in Qt's
initialization, usually as a result of some debug message, via
QLoggingRegistry::initializeRules(). This bypasses the need to create
QResourceFileEnginePrivate, QResourceFileEngine, QFileInfoPrivate, and
QFileInfo, all of which would end up in this .isValid() call.
Additionally, I'm making it query in the C locale, which will also avoid
initializing the system & default QLocales. If a resource exists in any
language, the C locale query will find it.
Task-number: QTBUG-133206
Change-Id: I434b498903d793c12d35fffd3e297bfdbdc1b6fe
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit d59e640c868f3db2d661970f3d34a22013d49053)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit ae2502b4ad3d1215211bf4ed44037a40f52a313d)
---
src/corelib/global/qlibraryinfo.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp
index 94f3e60deba..5f6042be29d 100644
--- a/src/corelib/global/qlibraryinfo.cpp
+++ b/src/corelib/global/qlibraryinfo.cpp
@@ -6,6 +6,7 @@
#include "qstringlist.h"
#include "qfile.h"
#if QT_CONFIG(settings)
+#include "qresource.h"
#include "qsettings.h"
#endif
#include "qlibraryinfo.h"
@@ -103,7 +104,7 @@ static std::unique_ptr<QSettings> findConfiguration()
return std::make_unique<QSettings>(*qtconfManualPath, QSettings::IniFormat);
QString qtconfig = QStringLiteral(":/qt/etc/qt.conf");
- if (QFile::exists(qtconfig))
+ if (QResource(qtconfig, QLocale::c()).isValid())
return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
#ifdef Q_OS_DARWIN
CFBundleRef bundleRef = CFBundleGetMainBundle();
--
GitLab

View file

@ -1,48 +0,0 @@
From 2ef615228bba9a8eb282437bfb7472f925610e89 Mon Sep 17 00:00:00 2001
From: Thiago Macieira <thiago.macieira@intel.com>
Date: Fri, 24 Jan 2025 10:28:30 -0800
Subject: [PATCH] QSystemLocale: bail out if accessed post-destruction
There's little we can do, but a lot of content ends up in QLocale very
late in the execution. Let's at least not crash.
Task-number: QTBUG-133206
Change-Id: I77d41141cb115147f9befffdd5e69dac19c96044
Reviewed-by: Albert Astals Cid <aacid@kde.org>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
(cherry picked from commit e32f28034ad2383393645777bcd96eab3f696076)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit d5c5f9f3529b384d0d4bea2d51f0ad6a3d57481d)
---
src/corelib/text/qlocale_unix.cpp | 2 ++
src/corelib/text/qlocale_win.cpp | 2 ++
2 files changed, 4 insertions(+)
diff --git a/src/corelib/text/qlocale_unix.cpp b/src/corelib/text/qlocale_unix.cpp
index a934f24c016..91dbb74c207 100644
--- a/src/corelib/text/qlocale_unix.cpp
+++ b/src/corelib/text/qlocale_unix.cpp
@@ -127,6 +127,8 @@ QLocale QSystemLocale::fallbackLocale() const
QVariant QSystemLocale::query(QueryType type, QVariant &&in) const
{
QSystemLocaleData *d = qSystemLocaleData();
+ if (!d)
+ return QVariant();
if (type == LocaleChanged) {
d->readEnvironment();
diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp
index 9fdb46a4c92..793751daaf0 100644
--- a/src/corelib/text/qlocale_win.cpp
+++ b/src/corelib/text/qlocale_win.cpp
@@ -828,6 +828,8 @@ QLocale QSystemLocale::fallbackLocale() const
QVariant QSystemLocale::query(QueryType type, QVariant &&in) const
{
QSystemLocalePrivate *d = systemLocalePrivate();
+ if (!d)
+ return QVariant();
switch(type) {
case DecimalPoint:
return d->decimalPoint();
--
GitLab

View file

@ -1,48 +0,0 @@
From 12d4bf1ab52748cb84894f50d437064b439e0b7d Mon Sep 17 00:00:00 2001
From: Thiago Macieira <thiago.macieira@intel.com>
Date: Fri, 24 Jan 2025 10:43:38 -0800
Subject: [PATCH] QLocale: try to survive being created during application shut
down
QLocale is very often accessed during global static destructors, so
let's try and survive if the default has already been destroyed. In that
case, we shall fall back to the C locale.
I've placed the call to systemData(), which updates the system locale,
before the initialization of defaultLocalePrivate, as the initialization
of the latter depends on the former.
Task-number: QTBUG-133206
Change-Id: I48e29b45f9be4514336cfffdf5affa5631a956a3
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Albert Astals Cid <aacid@kde.org>
(cherry picked from commit e0a1f491567f2495443babc5aa36a038260f96c6)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit bcc0e6124a2ec80df535178d056324433f9ff984)
---
src/corelib/text/qlocale.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index 4f5b5452648..eff083b3d94 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -1112,10 +1112,13 @@ QLocale::QLocale(QStringView name)
*/
QLocale::QLocale()
- : d(*defaultLocalePrivate)
+ : d(c_private())
{
- // Make sure system data is up to date:
- systemData();
+ if (!defaultLocalePrivate.isDestroyed()) {
+ // Make sure system data is up to date:
+ systemData();
+ d = *defaultLocalePrivate;
+ }
}
/*!
--
GitLab

View file

@ -1,45 +0,0 @@
From 0acbd22508cb793461c01979d89c529f86a24bc3 Mon Sep 17 00:00:00 2001
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Date: Wed, 15 Jan 2025 15:12:41 +0100
Subject: [PATCH] Request actual font family request in final color font fail safe
When we're trying to resolve a font for color emojis, we will
prefer any color font over the selected font (since a normal
font may have monochrome glyphs for emoji characters and that's
not what we are after).
If there are no color fonts on the system at all, we need to do
a final match where we ignore whether the font is in color or
not and just return it anyway.
In this final pass we would find the first best match among the
fallbacks (typically the first one), but never actually check
the font that was requested in the first place. This was a
mistake. Unless it does not exist, we should just return the
requested font family.
Pick-to: 6.9
Task-number: QTBUG-132377
Change-Id: Ie53a6bd665ebdaaca92bf0c33fabf5195e1aa5fe
---
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 0c2a4b66..03f29009 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -2787,8 +2787,14 @@ QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &req,
// If we are looking for a color font and there are no color fonts on the system,
// we will end up here, for one final pass. This is a rare occurrence so we accept
// and extra pass on the fallbacks for this.
- if (!engine && script == QFontDatabasePrivate::Script_Emoji)
+ if (!engine && script == QFontDatabasePrivate::Script_Emoji) {
engine = findMatchingFallback(QChar::Script_Common, script);
+
+ // Since we no longer require color fonts, we need to retry to check if the
+ // actual requested font is available as a non-color font.
+ if (!requestFamily.isEmpty())
+ fallbacks.prepend(requestFamily);
+ }
}
if (!engine)

View file

@ -1,15 +0,0 @@
diff --git a/cmake/QtPublicWalkLibsHelpers.cmake b/cmake/QtPublicWalkLibsHelpers.cmake
index 959283ac..d2d6d70e 100644
--- a/cmake/QtPublicWalkLibsHelpers.cmake
+++ b/cmake/QtPublicWalkLibsHelpers.cmake
@@ -255,8 +255,8 @@ function(__qt_internal_walk_libs
__qt_internal_promote_target_to_global(${lib_target_unaliased})
endif()
endif()
- elseif("${lib_target}" MATCHES "^(Qt|${QT_CMAKE_EXPORT_NAMESPACE})::(.*)")
- message(FATAL_ERROR "The ${CMAKE_MATCH_2} target is mentioned as a dependency for \
+ elseif("${lib_target}" MATCHES "^Qt::(.*)")
+ message(FATAL_ERROR "The ${CMAKE_MATCH_1} target is mentioned as a dependency for \
${target}, but not declared.")
else()
if(NOT operation MATCHES "^(collect|direct)_targets$")

View file

@ -1,55 +0,0 @@
From cb2633468413d8c2a9e28d4c4a10b25e90dd3116 Mon Sep 17 00:00:00 2001
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Date: Mon, 25 Nov 2024 16:05:09 +0100
Subject: Skip ad hoc handling of variation selector in font merging
Since we now support emoji parsing, there is no longer any need
for this ad hoc processing of VS-16. The exception is if Qt is
built without the emoji segmenter, in which case we should keep
it for consistency with previous versions.
Task-number: QTBUG-111801
Change-Id: I3e243b9610fe55dda26eba63ac849e6afa22a185
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 02595b40c5..6be6a5aca2 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -1997,8 +1997,11 @@ int QFontEngineMulti::stringToCMap(const QChar *str, int len,
int glyph_pos = 0;
QStringIterator it(str, str + len);
- int lastFallback = -1;
+#if defined(QT_NO_EMOJISEGMENTER)
char32_t previousUcs4 = 0;
+#endif
+
+ int lastFallback = -1;
while (it.hasNext()) {
const char32_t ucs4 = it.peekNext();
@@ -2057,6 +2060,7 @@ int QFontEngineMulti::stringToCMap(const QChar *str, int len,
}
}
+#if defined(QT_NO_EMOJISEGMENTER)
// For variant-selectors, they are modifiers to the previous character. If we
// end up with different font selections for the selector and the character it
// modifies, we try applying the selector font to the preceding character as well
@@ -2095,11 +2099,15 @@ int QFontEngineMulti::stringToCMap(const QChar *str, int len,
}
}
}
+#endif
}
it.advance();
++glyph_pos;
+
+#if defined(QT_NO_EMOJISEGMENTER)
previousUcs4 = ucs4;
+#endif
}
*nglyphs = glyph_pos;

View file

@ -1,115 +0,0 @@
From aaf7437db3a520ab14220a46cf9427cb9a8d915c Mon Sep 17 00:00:00 2001
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Date: Fri, 29 Nov 2024 15:27:10 +0100
Subject: [PATCH] Support variation selector when emoji segmenter is disabled
This amends cb2633468413d8c2a9e28d4c4a10b25e90dd3116.
The patch excluded the ad hoc parsing of variation selector
except when Qt was built without the emoji segmenter. The
reasoning being that the emoji parsing handles this correctly
now.
However, when setting the QT_DISABLE_EMOJI_SEGMENTER variable
in the environment, this is supposed to work as a fail safe
which gives you the original behavior, in case there are
regressions. Therefore, the variation selector handling needs
to be run also when this environment variable is set.
Pick-to: 6.9
Change-Id: I2669d29016a552775461aad13e50459baecdc26f
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
---
src/gui/text/qfontengine.cpp | 19 ++++++++++++-------
src/gui/text/qfontengine_p.h | 2 ++
src/gui/text/qtextengine.cpp | 3 +--
3 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index b5183dfd..60d46c5b 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -1526,6 +1526,16 @@ QFontEngine::GlyphCacheEntry &QFontEngine::GlyphCacheEntry::operator=(const Glyp
return *this;
}
+bool QFontEngine::disableEmojiSegmenter()
+{
+#if defined(QT_NO_EMOJISEGMENTER)
+ return true;
+#else
+ static const bool sDisableEmojiSegmenter = qEnvironmentVariableIntValue("QT_DISABLE_EMOJI_SEGMENTER") > 0;
+ return sDisableEmojiSegmenter;
+#endif
+}
+
// ------------------------------------------------------------------
// The box font engine
// ------------------------------------------------------------------
@@ -1884,9 +1894,8 @@ int QFontEngineMulti::stringToCMap(const QChar *str, int len,
int glyph_pos = 0;
QStringIterator it(str, str + len);
-#if defined(QT_NO_EMOJISEGMENTER)
+ const bool enableVariationSelectorHack = disableEmojiSegmenter();
char32_t previousUcs4 = 0;
-#endif
int lastFallback = -1;
while (it.hasNext()) {
@@ -1947,12 +1956,11 @@ int QFontEngineMulti::stringToCMap(const QChar *str, int len,
}
}
-#if defined(QT_NO_EMOJISEGMENTER)
// For variant-selectors, they are modifiers to the previous character. If we
// end up with different font selections for the selector and the character it
// modifies, we try applying the selector font to the preceding character as well
const int variantSelectorBlock = 0xFE00;
- if ((ucs4 & 0xFFF0) == variantSelectorBlock && glyph_pos > 0) {
+ if (enableVariationSelectorHack && (ucs4 & 0xFFF0) == variantSelectorBlock && glyph_pos > 0) {
int selectorFontEngine = glyphs->glyphs[glyph_pos] >> 24;
int precedingCharacterFontEngine = glyphs->glyphs[glyph_pos - 1] >> 24;
@@ -1986,15 +1994,12 @@ int QFontEngineMulti::stringToCMap(const QChar *str, int len,
}
}
}
-#endif
}
it.advance();
++glyph_pos;
-#if defined(QT_NO_EMOJISEGMENTER)
previousUcs4 = ucs4;
-#endif
}
*nglyphs = glyph_pos;
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index b56c3792..9ef4b29d 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -255,6 +255,8 @@ public:
virtual bool hasUnreliableGlyphOutline() const;
virtual bool expectsGammaCorrectedBlending() const;
+ static bool disableEmojiSegmenter();
+
enum HintStyle {
HintNone,
HintLight,
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index a04cd9a7..8d13517f 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -1953,7 +1953,7 @@ namespace {
void QTextEngine::itemize() const
{
- static bool disableEmojiSegmenter = qEnvironmentVariableIntValue("QT_DISABLE_EMOJI_SEGMENTER") > 0;
+ const bool disableEmojiSegmenter = QFontEngine::disableEmojiSegmenter();
validate();
if (layoutData->items.size())
return;

View file

@ -1,54 +0,0 @@
From dc87345703228bd3e86da74d7fd22e77c81f6056 Mon Sep 17 00:00:00 2001
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Date: Wed, 12 Feb 2025 13:58:36 +0100
Subject: [PATCH] Treat variation selectors as ignorable chars
The variation selectors only make sense in the context of the
previous glyph and should never be shaped by themselves, therefore
we should not pick a different font engine for these even if
the cmap does not support it. They are sometimes needed to
properly resolve the emojis, but the OpenType rules in the font
may not be written with them in mind.
If the cmap lookup fails for these, then Harfbuzz will map them
to a zero-width space, thus ignoring them when resolving the
OpenType rules.
We treat these the same as other control characters and just
ignore them when doing font merging.
Note: This was handled through an ad hoc mechanism prior to
the introduction of the emoji segmenter in 6.9.When the emoji
segmenter is disabled, we still use this mechanism, which
depends on us not ignoring the character in that case.
Pick-to: 6.9
Fixes: QTBUG-133480
Change-Id: I8fa4e8d5e1aabad0946b8fd3fff044e2b2af5d0e
---
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 032a8b7..4d1243c 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -159,6 +159,7 @@
|| ucs4 == QChar::LineFeed
|| ucs4 == QChar::CarriageReturn
|| ucs4 == QChar::ParagraphSeparator
+ || (!disableEmojiSegmenter() && (ucs4 & 0xFFF0) == 0xFE00)
|| QChar::category(ucs4) == QChar::Other_Control;
}
diff --git a/tests/baseline/painting/scripts/glyphruns.qps b/tests/baseline/painting/scripts/glyphruns.qps
index 2b70c72..0683ef5 100644
--- a/tests/baseline/painting/scripts/glyphruns.qps
+++ b/tests/baseline/painting/scripts/glyphruns.qps
@@ -143,7 +143,7 @@
save
setPen black
setFont "sansserif" 16 normal
- drawGlyphRun 0 40 "e😃m😇o😍j😜i😸!"
+ drawGlyphRun 0 40 "e😃m👩o😍j😜i😸!"
restore
translate 0 55

View file

@ -0,0 +1,174 @@
From 095759818854e5a011aa8f859e566bbc6368ab76 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= <mumei6102@gmail.com>
Date: Sun, 27 Jul 2025 00:50:00 +0200
Subject: [PATCH] wayland: Compress high frequency mouse events
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add support for Qt::AA_CompressHighFrequencyEvents on Wayland.
The highest USB HID polling rate is 8 kHz (125 μs). Most mice use lower
polling rate [125 Hz - 1000 Hz]. Reject all events faster than 100 μs,
because it definitely means the application main thread is freezed by
the long operation and events are delivered one after another from the
queue. Since now we rely on the 0 ms timer to deliver the last pending
event when application main thread is no longer freezed.
Pick-to: 6.10
Task-number: QTBUG-138706
Change-Id: Ie9d539e233c5551b1756d599b65495571e195f9d
Reviewed-by: David Edmundson <davidedmundson@kde.org>
---
src/corelib/global/qnamespace.qdoc | 1 +
.../platforms/wayland/qwaylandinputdevice.cpp | 38 +++++++++++++++++++
.../platforms/wayland/qwaylandinputdevice_p.h | 12 ++++++
.../platforms/wayland/qwaylandintegration.cpp | 2 +
tests/auto/wayland/client/tst_client.cpp | 2 +
5 files changed, 55 insertions(+)
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index c845cfa7..f463d736 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -227,6 +227,7 @@
application later.
On Windows 8 and above the default value is also true, but it only applies
to touch events. Mouse and window events remain unaffected by this flag.
+ On Wayland the default value is also true, but it only applies to mouse events.
On other platforms, the default is false.
(In the future, the compression feature may be implemented across platforms.)
You can test the attribute to see whether compression is enabled.
diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
index 170e80f8..45c78765 100644
--- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
+++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
@@ -63,6 +63,34 @@ Q_LOGGING_CATEGORY(lcQpaWaylandInput, "qt.qpa.wayland.input");
// reasonable number of them. As of 2021 most touchscreen panels support 10 concurrent touchpoints.
static const int MaxTouchPoints = 10;
+QWaylandEventCompressionPrivate::QWaylandEventCompressionPrivate()
+{
+ timeElapsed.start();
+ delayTimer.setSingleShot(true);
+}
+
+bool QWaylandEventCompressionPrivate::compressEvent()
+{
+ using namespace std::chrono_literals;
+
+ if (!QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents))
+ return false;
+
+ const auto elapsed = timeElapsed.durationElapsed();
+ timeElapsed.start();
+ if (elapsed < 100us || delayTimer.isActive())
+ {
+ // The highest USB HID polling rate is 8 kHz (125 μs). Most mice use lowe polling rate [125 Hz - 1000 Hz].
+ // Reject all events faster than 100 μs, because it definitely means the application main thread is
+ // freezed by long operation and events are delivered one after another from the queue. Since now we rely
+ // on the 0 ms timer to deliver the last pending event when application main thread is no longer freezed.
+ delayTimer.start(0);
+ return true;
+ }
+
+ return false;
+}
+
QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p)
: mParent(p)
{
@@ -140,6 +168,8 @@ QWaylandInputDevice::Pointer::Pointer(QWaylandInputDevice *seat)
cursorTimerCallback();
});
#endif
+
+ mEventCompression.delayTimer.callOnTimeout(this, &QWaylandInputDevice::Pointer::flushFrameEvent);
}
QWaylandInputDevice::Pointer::~Pointer()
@@ -922,6 +952,11 @@ void QWaylandInputDevice::Pointer::pointer_axis(uint32_t time, uint32_t axis, in
void QWaylandInputDevice::Pointer::pointer_frame()
{
+ if (mEventCompression.compressEvent()) {
+ qCDebug(lcQpaWaylandInput) << "compressed pointer_frame event";
+ return;
+ }
+
flushFrameEvent();
}
@@ -1051,6 +1086,7 @@ void QWaylandInputDevice::Pointer::setFrameEvent(QWaylandPointerEvent *event)
flushFrameEvent();
}
+ delete mFrameData.event;
mFrameData.event = event;
if (version() < WL_POINTER_FRAME_SINCE_VERSION) {
@@ -1170,6 +1206,8 @@ void QWaylandInputDevice::Pointer::flushScrollEvent()
void QWaylandInputDevice::Pointer::flushFrameEvent()
{
+ mEventCompression.delayTimer.stop();
+
if (auto *event = mFrameData.event) {
if (auto window = event->surface) {
window->handleMouse(mParent, *event);
diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
index bcaf0258..0b24999e 100644
--- a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
+++ b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
@@ -75,6 +75,16 @@ class CursorSurface;
Q_DECLARE_LOGGING_CATEGORY(lcQpaWaylandInput);
+struct QWaylandEventCompressionPrivate
+{
+ QWaylandEventCompressionPrivate();
+
+ bool compressEvent();
+
+ QElapsedTimer timeElapsed;
+ QTimer delayTimer;
+};
+
class Q_WAYLANDCLIENT_EXPORT QWaylandInputDevice
: public QObject
, public QtWayland::wl_seat
@@ -381,6 +391,8 @@ public:
bool mScrollBeginSent = false;
QPointF mScrollDeltaRemainder;
+ QWaylandEventCompressionPrivate mEventCompression;
+
void setFrameEvent(QWaylandPointerEvent *event);
void flushScrollEvent();
void flushFrameEvent();
diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp
index 669d47ee..fc869de6 100644
--- a/src/plugins/platforms/wayland/qwaylandintegration.cpp
+++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp
@@ -87,6 +87,8 @@ QWaylandIntegration::QWaylandIntegration(const QString &platformName)
: mPlatformName(platformName), mFontDb(new QGenericUnixFontDatabase())
#endif
{
+ QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
+
mDisplay.reset(new QWaylandDisplay(this));
mPlatformServices.reset(new QWaylandPlatformServices(mDisplay.data()));
diff --git a/tests/auto/wayland/client/tst_client.cpp b/tests/auto/wayland/client/tst_client.cpp
index 04400e3f..09ac4f7f 100644
--- a/tests/auto/wayland/client/tst_client.cpp
+++ b/tests/auto/wayland/client/tst_client.cpp
@@ -276,6 +276,8 @@ void tst_WaylandClient::events()
exec([&] {
pointer()->sendEnter(s, window.frameOffset() + mousePressPos);
pointer()->sendFrame(client());
+ pointer()->sendMotion(client(), window.frameOffset() + mousePressPos / 2);
+ pointer()->sendFrame(client());
pointer()->sendMotion(client(), window.frameOffset() + mousePressPos);
pointer()->sendFrame(client());
pointer()->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);

View file

@ -0,0 +1,55 @@
From 18550cd9ad04913d50abfc88a6048b7cfaf80687 Mon Sep 17 00:00:00 2001
From: Igor Khanin <igor@khanin.biz>
Date: Mon, 13 Oct 2025 14:26:39 +0300
Subject: [PATCH] wayland: Convey preference for server side decorations
As discussed in the mailing list, Qt applications generally expect top
level windows to be decorated by the windowing system - unless
explicitly requested by the developer by marking a window as frameless.
Furthermore, Qt's client side decorations for Wayland were only really
intended as a fallback.
However until now the Wayland xdg-shell integration conveyed to the
compositor (if it supports decorations negotiations) that it didn't
care whose responsibility it was to draw window decorations. This did
not matter under KWin, which resolves such cases in favor of SSDs - but
does matter under other SSD-capable compositors like cosmic-comp (which
considers SSDs to be the fallback option).
This changes the xdg-shell integration code to be explicit about
requesting SSDs.
[ChangeLog][QtWaylandClient][Important Behavior Changes] The Wayland
XDG shell integration now requests server side decorations with
compositors supporting the zxdg_decoration_manager_v1 protocol.
Change-Id: Ia025b1f6ff17248a5710f981a0cecd90c47b6cd8
Reviewed-by: David Edmundson <davidedmundson@kde.org>
---
diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
index a1a173f..8386b65 100644
--- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
+++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
@@ -201,7 +201,7 @@
delete m_decoration;
m_decoration = nullptr;
} else {
- m_decoration->unsetMode();
+ m_decoration->requestMode(QWaylandXdgToplevelDecorationV1::mode_server_side);
}
}
}
diff --git a/tests/auto/wayland/xdgdecorationv1/tst_xdgdecorationv1.cpp b/tests/auto/wayland/xdgdecorationv1/tst_xdgdecorationv1.cpp
index 5ee8569..65ac08f 100644
--- a/tests/auto/wayland/xdgdecorationv1/tst_xdgdecorationv1.cpp
+++ b/tests/auto/wayland/xdgdecorationv1/tst_xdgdecorationv1.cpp
@@ -149,7 +149,7 @@
QVERIFY(window.frameMargins().isNull());
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- QCOMPOSITOR_TRY_VERIFY(toplevelDecoration()->m_unsetModeRequested);
+ QCOMPOSITOR_TRY_VERIFY(toplevelDecoration()->m_requestedMode == XdgToplevelDecorationV1::mode_server_side);
QVERIFY(window.frameMargins().isNull()); // We're still waiting for a configure
exec([&] {
toplevelDecoration()->sendConfigure(XdgToplevelDecorationV1::mode_client_side);

View file

@ -0,0 +1,235 @@
From 9dd0d936d6691904a4bb212dcf48999a5228b84f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= <mumei6102@gmail.com>
Date: Thu, 7 Aug 2025 15:42:55 +0200
Subject: [PATCH] wayland: Enable event compression and fix scroll end event
We have to deliver the scroll end event in order with other scroll
events, so move scroll end event logic into flushScrollEvent().
Track the target scroll window on scroll begin and check whether we
have a target window to prevent a crash.
Also we can't clear the scroll delta when scroll end event arrives,
because the event compression relies on this value.
Use scoped pointer for frame event to simplify code and make sure it's
deleted in destructor.
Amends 095759818854e5a011aa8f859e566bbc6368ab76
Updates 789681872fb62450fc78d1a06472a40d970a8d57
Change-Id: Ifb149c8fde1286b60439be0dab16b1df65279ea8
Reviewed-by: David Edmundson <davidedmundson@kde.org>
---
.../platforms/wayland/qwaylandinputdevice.cpp | 98 ++++++++++---------
.../platforms/wayland/qwaylandinputdevice_p.h | 6 +-
.../platforms/wayland/qwaylandintegration.cpp | 2 +
3 files changed, 61 insertions(+), 45 deletions(-)
diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
index 7fcda34c57ca..6ce43714a35f 100644
--- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
+++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
@@ -935,10 +935,7 @@ void QWaylandInputDevice::Pointer::pointer_axis(uint32_t time, uint32_t axis, in
mParent->mTime = time;
- if (version() < WL_POINTER_FRAME_SINCE_VERSION) {
- qCDebug(lcQpaWaylandInput) << "Flushing new event; no frame event in this version";
- flushFrameEvent();
- }
+ maybePointerFrame();
}
void QWaylandInputDevice::Pointer::pointer_frame()
@@ -978,11 +975,9 @@ void QWaylandInputDevice::Pointer::pointer_axis_stop(uint32_t time, uint32_t axi
switch (axis) {
case axis_vertical_scroll:
qCDebug(lcQpaWaylandInput) << "Received vertical wl_pointer.axis_stop";
- mFrameData.delta.setY(0); //TODO: what's the point of doing this?
break;
case axis_horizontal_scroll:
qCDebug(lcQpaWaylandInput) << "Received horizontal wl_pointer.axis_stop";
- mFrameData.delta.setX(0);
break;
default:
qCWarning(lcQpaWaylandInput) << "wl_pointer.axis_stop: Unknown axis: " << axis
@@ -990,25 +985,7 @@ void QWaylandInputDevice::Pointer::pointer_axis_stop(uint32_t time, uint32_t axi
return;
}
- // May receive axis_stop for events we haven't sent a ScrollBegin for because
- // most axis_sources do not mandate an axis_stop event to be sent.
- if (!mScrollBeginSent) {
- // TODO: For now, we just ignore these events, but we could perhaps take this as an
- // indication that this compositor will in fact send axis_stop events for these sources
- // and send a ScrollBegin the next time an axis_source event with this type is encountered.
- return;
- }
-
- QWaylandWindow *target = QWaylandWindow::mouseGrab();
- if (!target)
- target = focusWindow();
- Qt::KeyboardModifiers mods = mParent->modifiers();
- const bool inverted = mFrameData.verticalAxisInverted || mFrameData.horizontalAxisInverted;
- WheelEvent wheelEvent(focusWindow(), Qt::ScrollEnd, mParent->mTime, mSurfacePos, mGlobalPos,
- QPoint(), QPoint(), Qt::MouseEventNotSynthesized, mods, inverted);
- target->handleMouse(mParent, wheelEvent);
- mScrollBeginSent = false;
- mScrollDeltaRemainder = QPointF();
+ mScrollEnd = true;
}
void QWaylandInputDevice::Pointer::pointer_axis_discrete(uint32_t axis, int32_t value)
@@ -1069,6 +1046,14 @@ void QWaylandInputDevice::Pointer::pointer_axis_relative_direction(uint32_t axis
}
}
+inline void QWaylandInputDevice::Pointer::maybePointerFrame()
+{
+ if (version() < WL_POINTER_FRAME_SINCE_VERSION) {
+ qCDebug(lcQpaWaylandInput) << "Flushing new event; no frame event in this version";
+ pointer_frame();
+ }
+}
+
void QWaylandInputDevice::Pointer::setFrameEvent(QWaylandPointerEvent *event)
{
qCDebug(lcQpaWaylandInput) << "Setting frame event " << event->type;
@@ -1077,13 +1062,9 @@ void QWaylandInputDevice::Pointer::setFrameEvent(QWaylandPointerEvent *event)
flushFrameEvent();
}
- delete mFrameData.event;
- mFrameData.event = event;
+ mFrameData.event.reset(event);
- if (version() < WL_POINTER_FRAME_SINCE_VERSION) {
- qCDebug(lcQpaWaylandInput) << "Flushing new event; no frame event in this version";
- flushFrameEvent();
- }
+ maybePointerFrame();
}
void QWaylandInputDevice::Pointer::FrameData::resetScrollData()
@@ -1163,11 +1144,24 @@ void QWaylandInputDevice::Pointer::flushScrollEvent()
{
QPoint angleDelta = mFrameData.angleDelta();
+ // The wayland protocol has separate horizontal and vertical axes, Qt has just the one inverted flag
+ // Pragmatically it should't come up
+ const bool inverted = mFrameData.verticalAxisInverted || mFrameData.horizontalAxisInverted;
+
// Angle delta is required for Qt wheel events, so don't try to send events if it's zero
if (!angleDelta.isNull()) {
- QWaylandWindow *target = QWaylandWindow::mouseGrab();
- if (!target)
- target = focusWindow();
+ QWaylandWindow *target = mScrollTarget;
+ if (!mScrollBeginSent) {
+ if (!target)
+ target = QWaylandWindow::mouseGrab();
+ if (!target)
+ target = focusWindow();
+ }
+ if (!target) {
+ qCDebug(lcQpaWaylandInput) << "Flushing scroll event aborted - no scroll target";
+ mFrameData.resetScrollData();
+ return;
+ }
if (isDefinitelyTerminated(mFrameData.axisSource) && !mScrollBeginSent) {
qCDebug(lcQpaWaylandInput) << "Flushing scroll event sending ScrollBegin";
@@ -1177,21 +1171,38 @@ void QWaylandInputDevice::Pointer::flushScrollEvent()
mParent->modifiers(), false));
mScrollBeginSent = true;
mScrollDeltaRemainder = QPointF();
+ mScrollTarget = target;
}
Qt::ScrollPhase phase = mScrollBeginSent ? Qt::ScrollUpdate : Qt::NoScrollPhase;
QPoint pixelDelta = mFrameData.pixelDeltaAndError(&mScrollDeltaRemainder);
- Qt::MouseEventSource source = mFrameData.wheelEventSource();
-
-
- // The wayland protocol has separate horizontal and vertical axes, Qt has just the one inverted flag
- // Pragmatically it should't come up
- const bool inverted = mFrameData.verticalAxisInverted || mFrameData.horizontalAxisInverted;
qCDebug(lcQpaWaylandInput) << "Flushing scroll event" << phase << pixelDelta << angleDelta;
target->handleMouse(mParent, WheelEvent(focusWindow(), phase, mParent->mTime, mSurfacePos, mGlobalPos,
- pixelDelta, angleDelta, source, mParent->modifiers(), inverted));
+ pixelDelta, angleDelta, mFrameData.wheelEventSource(), mParent->modifiers(), inverted));
+ }
+
+ if (mScrollEnd) {
+ if (mScrollBeginSent) {
+ if (auto target = mScrollTarget.get()) {
+ qCDebug(lcQpaWaylandInput) << "Flushing scroll end event";
+ target->handleMouse(mParent, WheelEvent(focusWindow(), Qt::ScrollEnd, mParent->mTime, mSurfacePos, mGlobalPos,
+ QPoint(), QPoint(), mFrameData.wheelEventSource(), mParent->modifiers(), inverted));
+ }
+ mScrollBeginSent = false;
+ mScrollDeltaRemainder = QPointF();
+ } else {
+ // May receive axis_stop for events we haven't sent a ScrollBegin for because
+ // most axis_sources do not mandate an axis_stop event to be sent.
+
+ // TODO: For now, we just ignore these events, but we could perhaps take this as an
+ // indication that this compositor will in fact send axis_stop events for these sources
+ // and send a ScrollBegin the next time an axis_source event with this type is encountered.
+ }
+ mScrollEnd = false;
+ mScrollTarget.clear();
}
+
mFrameData.resetScrollData();
}
@@ -1199,7 +1210,7 @@ void QWaylandInputDevice::Pointer::flushFrameEvent()
{
mEventCompression.delayTimer.stop();
- if (auto *event = mFrameData.event) {
+ if (auto *event = mFrameData.event.get()) {
if (auto window = event->surface) {
window->handleMouse(mParent, *event);
} else if (mFrameData.event->type == QEvent::MouseButtonRelease) {
@@ -1212,8 +1223,7 @@ void QWaylandInputDevice::Pointer::flushFrameEvent()
event->modifiers); // , Qt::MouseEventSource source =
// Qt::MouseEventNotSynthesized);
}
- delete mFrameData.event;
- mFrameData.event = nullptr;
+ mFrameData.event.reset();
}
//TODO: do modifiers get passed correctly here?
diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
index 533a10991e5e..aa2ccddbcdb8 100644
--- a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
+++ b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h
@@ -370,7 +370,7 @@ private Q_SLOTS:
Qt::MouseButton mLastButton = Qt::NoButton;
struct FrameData {
- QWaylandPointerEvent *event = nullptr;
+ QScopedPointer<QWaylandPointerEvent> event;
QPointF delta;
QPoint delta120;
@@ -387,10 +387,14 @@ private Q_SLOTS:
} mFrameData;
bool mScrollBeginSent = false;
+ bool mScrollEnd = false;
QPointF mScrollDeltaRemainder;
+ QPointer<QWaylandWindow> mScrollTarget;
QWaylandEventCompressionPrivate mEventCompression;
+ void maybePointerFrame();
+
void setFrameEvent(QWaylandPointerEvent *event);
void flushScrollEvent();
void flushFrameEvent();

View file

@ -0,0 +1,39 @@
From c93008e4d06abb0072e0e5e57d84a4ae182ecfc0 Mon Sep 17 00:00:00 2001
From: Błażej Szczygieł <mumei6102@gmail.com>
Date: Tue, 21 Oct 2025 19:49:17 +0200
Subject: [PATCH] wayland: Fix crash in QWaylandShmBackingStore::scroll()
Fixes a crash when monitor is unplugged while scrolling.
recreateBackBufferIfNeeded() calls getBuffer() which may set
mFrontBuffer to nullptr.
Amends: 6f25f703fd37a900c139e14a33a4639502bfeae7
Task-number: QTBUG-139231
Change-Id: Ia5bedce2a3f6580c722f73446de81a26d40ea2f4
Reviewed-by: David Edmundson <davidedmundson@kde.org>
---
diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
index b853db2..fa70b53 100644
--- a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
+++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
@@ -229,7 +229,7 @@
// Inspired by QCALayerBackingStore.
bool QWaylandShmBackingStore::scroll(const QRegion &region, int dx, int dy)
{
- if (Q_UNLIKELY(!mBackBuffer || !mFrontBuffer))
+ if (Q_UNLIKELY(!mBackBuffer))
return false;
const qreal devicePixelRatio = waylandWindow()->scale();
@@ -241,6 +241,8 @@
return false;
recreateBackBufferIfNeeded();
+ if (!mFrontBuffer)
+ return false;
const QPoint scrollDelta(dx, dy);
const QMargins margins = windowDecorationMargins();

View file

@ -0,0 +1,242 @@
From 6f25f703fd37a900c139e14a33a4639502bfeae7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= <mumei6102@gmail.com>
Date: Wed, 13 Aug 2025 00:48:08 +0200
Subject: [PATCH] wayland: Optimize scroll operation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Don't copy the dirty region in "recreateBackBufferIfNeeded()" in
"beginPaint()". Mark this region as non-dirty in the back buffer
and paint. Finalize the back buffer (copy remaining dirty region)
before flushing. This allows to optimize scrolling, we no longer
have to do a redundant dirty area copy.
This matches the "QCALayerBackingStore" logic.
Task-number: QTBUG-139231
Change-Id: I6c19491fa8f093de9c9ce7624d8f9b65b0b722c5
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: David Edmundson <davidedmundson@kde.org>
---
.../wayland/qwaylandshmbackingstore.cpp | 111 ++++++++++++------
.../wayland/qwaylandshmbackingstore_p.h | 3 +-
2 files changed, 74 insertions(+), 40 deletions(-)
diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
index d8fc7b18ca34..591e5064ebd6 100644
--- a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
+++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp
@@ -159,6 +159,8 @@ QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window, QWaylandDispla
// recreateBackBufferIfNeeded always resets mBackBuffer
if (mRequestedSize.isValid() && waylandWindow())
recreateBackBufferIfNeeded();
+ else
+ mBackBuffer = nullptr;
qDeleteAll(copy);
wl_event_queue_destroy(oldEventQueue);
});
@@ -183,11 +185,15 @@ QPaintDevice *QWaylandShmBackingStore::paintDevice()
void QWaylandShmBackingStore::updateDirtyStates(const QRegion &region)
{
- // Update dirty state of buffers based on what was painted. The back buffer will
- // not be dirty since we already painted on it, while other buffers will become dirty.
+ // Update dirty state of buffers based on what was painted. The back buffer will be
+ // less dirty, since we painted to it, while other buffers will become more dirty.
+ // This allows us to minimize copies between front and back buffers on swap in the
+ // cases where the painted region overlaps with the previous frame (front buffer).
for (QWaylandShmBuffer *b : std::as_const(mBuffers)) {
if (b != mBackBuffer)
b->dirtyRegion() += region;
+ else
+ b->dirtyRegion() -= region;
}
}
@@ -198,7 +204,7 @@ void QWaylandShmBackingStore::beginPaint(const QRegion &region)
const QMargins margins = windowDecorationMargins();
const QRegion regionTranslated = region.translated(margins.left(), margins.top());
- const bool bufferWasRecreated = recreateBackBufferIfNeeded(regionTranslated);
+ const bool bufferWasRecreated = recreateBackBufferIfNeeded();
updateDirtyStates(regionTranslated);
// Although undocumented, QBackingStore::beginPaint expects the painted region
@@ -223,7 +229,7 @@ void QWaylandShmBackingStore::endPaint()
// Inspired by QCALayerBackingStore.
bool QWaylandShmBackingStore::scroll(const QRegion &region, int dx, int dy)
{
- if (!mBackBuffer)
+ if (Q_UNLIKELY(!mBackBuffer || !mFrontBuffer))
return false;
const qreal devicePixelRatio = waylandWindow()->scale();
@@ -236,19 +242,35 @@ bool QWaylandShmBackingStore::scroll(const QRegion &region, int dx, int dy)
recreateBackBufferIfNeeded();
- QImage *backBufferImage = mBackBuffer->image();
-
const QPoint scrollDelta(dx, dy);
const QMargins margins = windowDecorationMargins();
const QRegion adjustedRegion = region.translated(margins.left(), margins.top());
- const QRect boundingRect = adjustedRegion.boundingRect();
- const QPoint devicePixelDelta = scrollDelta * devicePixelRatio;
+ const QRegion inPlaceRegion = adjustedRegion - mBackBuffer->dirtyRegion();
+ const QRegion frontBufferRegion = adjustedRegion - inPlaceRegion;
+
+ if (!inPlaceRegion.isEmpty()) {
+ const QRect inPlaceBoundingRect = inPlaceRegion.boundingRect();
+ const QPoint devicePixelDelta = scrollDelta * devicePixelRatio;
+
+ qt_scrollRectInImage(*mBackBuffer->image(),
+ QRect(inPlaceBoundingRect.topLeft() * devicePixelRatio,
+ inPlaceBoundingRect.size() * devicePixelRatio),
+ devicePixelDelta);
+ }
- qt_scrollRectInImage(*backBufferImage,
- QRect(boundingRect.topLeft() * devicePixelRatio,
- boundingRect.size() * devicePixelRatio),
- devicePixelDelta);
+ if (!frontBufferRegion.isEmpty()) {
+ QPainter painter(mBackBuffer->image());
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.scale(qreal(1) / devicePixelRatio, qreal(1) / devicePixelRatio);
+ for (const QRect &rect : frontBufferRegion) {
+ QRect sourceRect(rect.topLeft() * devicePixelRatio,
+ rect.size() * devicePixelRatio);
+ QRect destinationRect((rect.topLeft() + scrollDelta) * devicePixelRatio,
+ rect.size() * devicePixelRatio);
+ painter.drawImage(destinationRect, *mFrontBuffer->image(), sourceRect);
+ }
+ }
// We do not mark the source region as dirty, even though it technically has "moved".
// This matches the behavior of other backingstore implementations using qt_scrollRectInImage.
@@ -289,6 +311,8 @@ void QWaylandShmBackingStore::flush(QWindow *window, const QRegion &region, cons
if (windowDecoration() && windowDecoration()->isDirty())
updateDecorations();
+ finalizeBackBuffer();
+
mFrontBuffer = mBackBuffer;
QMargins margins = windowDecorationMargins();
@@ -313,6 +337,8 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size, bool &b
mBuffers.removeAt(i);
if (mBackBuffer == buffer)
mBackBuffer = nullptr;
+ if (mFrontBuffer == buffer)
+ mFrontBuffer = nullptr;
delete buffer;
}
}
@@ -341,7 +367,7 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size, bool &b
return nullptr;
}
-bool QWaylandShmBackingStore::recreateBackBufferIfNeeded(const QRegion &nonDirtyRegion)
+bool QWaylandShmBackingStore::recreateBackBufferIfNeeded()
{
wl_display_dispatch_queue_pending(mDisplay->wl_display(), mEventQueue);
@@ -375,30 +401,6 @@ bool QWaylandShmBackingStore::recreateBackBufferIfNeeded(const QRegion &nonDirty
qsizetype oldSizeInBytes = mBackBuffer ? mBackBuffer->image()->sizeInBytes() : 0;
qsizetype newSizeInBytes = buffer->image()->sizeInBytes();
- // mBackBuffer may have been deleted here but if so it means its size was different so we wouldn't copy it anyway
- if (mBackBuffer != buffer && oldSizeInBytes == newSizeInBytes) {
- const QRegion clipRegion = buffer->dirtyRegion() - nonDirtyRegion;
- const auto clipRects = clipRegion.rects();
- if (!clipRects.empty()) {
- Q_ASSERT(mBackBuffer);
- const QImage *sourceImage = mBackBuffer->image();
- QImage *targetImage = buffer->image();
-
- QPainter painter(targetImage);
- painter.setCompositionMode(QPainter::CompositionMode_Source);
- const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio();
- for (const QRect &clipRect : clipRects) { // Iterate clip rects, because complicated clip region causes higher CPU usage
- if (clipRects.size() > 1)
- painter.save();
- painter.setClipRect(clipRect);
- painter.scale(qreal(1) / targetDevicePixelRatio, qreal(1) / targetDevicePixelRatio);
- painter.drawImage(QRectF(QPointF(), targetImage->size()), *sourceImage, sourceImage->rect());
- if (clipRects.size() > 1)
- painter.restore();
- }
- }
- }
-
mBackBuffer = buffer;
for (QWaylandShmBuffer *buffer : std::as_const(mBuffers)) {
@@ -412,11 +414,40 @@ bool QWaylandShmBackingStore::recreateBackBufferIfNeeded(const QRegion &nonDirty
if (windowDecoration() && window()->isVisible() && oldSizeInBytes != newSizeInBytes)
windowDecoration()->update();
- buffer->dirtyRegion() = QRegion();
-
return bufferWasRecreated;
}
+void QWaylandShmBackingStore::finalizeBackBuffer()
+{
+ Q_ASSERT(mBackBuffer);
+
+ const QRegion clipRegion = mBackBuffer->dirtyRegion();
+ if (clipRegion.isEmpty())
+ return;
+
+ if (Q_UNLIKELY(!mFrontBuffer || mFrontBuffer == mBackBuffer))
+ return;
+
+ const QImage *sourceImage = mFrontBuffer->image();
+ QImage *targetImage = mBackBuffer->image();
+
+ QPainter painter(targetImage);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio();
+ const auto clipRects = clipRegion.rects();
+ for (const QRect &clipRect : clipRects) { // Iterate clip rects, because complicated clip region causes higher CPU usage
+ if (clipRects.size() > 1)
+ painter.save();
+ painter.setClipRect(clipRect);
+ painter.scale(qreal(1) / targetDevicePixelRatio, qreal(1) / targetDevicePixelRatio);
+ painter.drawImage(QRectF(QPointF(), targetImage->size()), *sourceImage, sourceImage->rect());
+ if (clipRects.size() > 1)
+ painter.restore();
+ }
+
+ mBackBuffer->dirtyRegion() = QRegion();
+}
+
QImage *QWaylandShmBackingStore::entireSurface() const
{
return mBackBuffer->image();
@@ -496,6 +527,8 @@ QImage QWaylandShmBackingStore::toImage() const
// instead of flush() for widgets that have renderToTexture children
// (QOpenGLWidget, QQuickWidget).
+ const_cast<QWaylandShmBackingStore *>(this)->finalizeBackBuffer();
+
return *contentSurface();
}
#endif // opengl
diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h b/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h
index efd80159e859..cfcafb283265 100644
--- a/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h
+++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h
@@ -73,7 +73,8 @@ class Q_WAYLANDCLIENT_EXPORT QWaylandShmBackingStore : public QPlatformBackingSt
QMargins windowDecorationMargins() const;
QImage *entireSurface() const;
QImage *contentSurface() const;
- bool recreateBackBufferIfNeeded(const QRegion &nonDirtyRegion = QRegion());
+ bool recreateBackBufferIfNeeded();
+ void finalizeBackBuffer();
QWaylandWindow *waylandWindow() const;
void iterateBuffer();

View file

@ -1 +1 @@
SHA512 (qtbase-everywhere-src-6.8.2.tar.xz) = 4a074aca1c8bcca536fd428c969c0119f5131d0d52b67028edbb75a81dc6e0c15394f69e29cef513e6d8c6e93384cedc38dd03b0eed6ab1bbafbe2b5bbc85799
SHA512 (qtbase-everywhere-src-6.10.1.tar.xz) = fd5dcdc59ec3b39e48563513ae438eb4540a28e72c46961295de2ccb08609289d477ef7e91aac0b8983f2d5b05b901b4f5be10eaca4ac4c6aa8cd598f37a228e