From 802b55bba2b87f236e24c2ef0dbc6a8143eaac29 Mon Sep 17 00:00:00 2001 From: Than Ngo Date: Sun, 28 May 2023 10:09:21 +0200 Subject: [PATCH] - add qt6 linuxui backend - backport: handle scale factor changes - backport: fix font double_scaling --- chromium-114-add_qt6_linuxui_backend.patch | 545 +++++++++++++++++ chromium-114-qt-fix_font_double_scaling.patch | 21 + ...m-114-qt-handle_scale_factor_changes.patch | 574 ++++++++++++++++++ chromium.spec | 15 +- 4 files changed, 1153 insertions(+), 2 deletions(-) create mode 100644 chromium-114-add_qt6_linuxui_backend.patch create mode 100644 chromium-114-qt-fix_font_double_scaling.patch create mode 100644 chromium-114-qt-handle_scale_factor_changes.patch diff --git a/chromium-114-add_qt6_linuxui_backend.patch b/chromium-114-add_qt6_linuxui_backend.patch new file mode 100644 index 00000000..fef27142 --- /dev/null +++ b/chromium-114-add_qt6_linuxui_backend.patch @@ -0,0 +1,545 @@ +commit 75f4b48eb71d4872ba3ac6c9fc3662a60eb4175d +Author: Tom Anderson +Date: Thu Apr 27 02:21:34 2023 +0000 + + Add QT6 LinuxUi backend + + - Enable QT6 by default on KDE6 + - If QT6 load fails, fallback to QT5 (and vice versa) + - Add use_qt6 build flag for packager control + - Add --qt-version runtime flag for user control + + R=thestig + + Change-Id: Ib1d9f6183663ecf7b9ddfe9d7f3e3442e534ccda + Fixed: 1434754 + Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4475369 + Commit-Queue: Thomas Anderson + Reviewed-by: Lei Zhang + Cr-Commit-Position: refs/heads/main@{#1136295} + +diff --git a/chrome/installer/linux/BUILD.gn b/chrome/installer/linux/BUILD.gn +index 5639b9ffc996e..3bacd3398d4a2 100644 +--- a/chrome/installer/linux/BUILD.gn ++++ b/chrome/installer/linux/BUILD.gn +@@ -109,6 +109,9 @@ if (use_qt) { + # to prevent a hard dependency on QT for the package. + packaging_files += [ "$root_out_dir/libqt5_shim.so" ] + } ++if (use_qt6) { ++ packaging_files += [ "$root_out_dir/libqt6_shim.so" ] ++} + + action_foreach("calculate_deb_dependencies") { + deps = [ ":installer_deps" ] +@@ -249,6 +252,12 @@ if (use_qt) { + deps = [ "//ui/qt:qt5_shim" ] + } + } ++if (use_qt6) { ++ strip_binary("strip_qt6_shim") { ++ binary_input = "$root_out_dir/libqt6_shim.so" ++ deps = [ "//ui/qt:qt6_shim" ] ++ } ++} + + # This target builds all "normal" Linux installers. You must set + # is_component_build=false before building this target. +@@ -447,6 +456,12 @@ group("installer_deps") { + "//ui/qt:qt5_shim", + ] + } ++ if (use_qt6) { ++ public_deps += [ ++ ":strip_qt6_shim", ++ "//ui/qt:qt6_shim", ++ ] ++ } + } + + # Creates .deb and .rpm (RPM for non-ChromeOS only) installer packages. +diff --git a/chrome/installer/linux/common/installer.include b/chrome/installer/linux/common/installer.include +index 8d76f1f280b01..439ef5ccb0f52 100644 +--- a/chrome/installer/linux/common/installer.include ++++ b/chrome/installer/linux/common/installer.include +@@ -254,6 +254,11 @@ stage_install_common() { + strippedfile="${OUTPUTDIR}/${file}.stripped" + install -m ${SHLIB_PERMS} "${strippedfile}" "${STAGEDIR}/${INSTALLDIR}/${file}" + fi ++ if [ -f "${OUTPUTDIR}/libqt6_shim.so" ]; then ++ file="libqt6_shim.so" ++ strippedfile="${OUTPUTDIR}/${file}.stripped" ++ install -m ${SHLIB_PERMS} "${strippedfile}" "${STAGEDIR}/${INSTALLDIR}/${file}" ++ fi + + # libc++ + if [ -f "${OUTPUTDIR}/lib/libc++.so" ]; then +diff --git a/ui/qt/BUILD.gn b/ui/qt/BUILD.gn +index bbede00daa4d0..6a67961edc2f7 100644 +--- a/ui/qt/BUILD.gn ++++ b/ui/qt/BUILD.gn +@@ -11,13 +11,6 @@ assert(use_qt) + assert(is_linux) + assert(!is_castos) + +-pkg_config("qt5_config") { +- packages = [ +- "Qt5Core", +- "Qt5Widgets", +- ] +-} +- + config("qt_internal_config") { + if (is_clang) { + # libstdc++ headers are incompatible with -fcomplete-member-pointers. +@@ -56,40 +49,57 @@ if (!use_sysroot) { + } + } + +-shared_library("qt5_shim") { +- visibility = [ +- ":qt", +- "//chrome/installer/linux:*", +- ] +- +- # Since qt_shim is a shared library even in non-component builds, it shouldn't +- # depend on any other targets since that would duplicate code between binaries +- # leading to increased size and potential issues from duplicated global state. +- no_default_deps = true +- assert_no_deps = [ +- "//base", +- "//buildtools/third_party/libc++", +- ] +- deps = [ ":qt_interface" ] +- +- configs -= [ "//build/config/compiler:runtime_library" ] +- configs += [ +- ":qt_internal_config", +- ":qt5_config", +- ] ++template("qt_shim") { ++ pkg_config("qt" + invoker.qt_version + "_config") { ++ packages = [ ++ "Qt" + invoker.qt_version + "Core", ++ "Qt" + invoker.qt_version + "Widgets", ++ ] ++ } + +- public = [] +- sources = [ +- "qt_shim.cc", +- "qt_shim.h", +- ] +- if (use_sysroot) { +- # This file is generated with gen_qt_shim_moc.sh on an amd64 system to +- # avoid a build-time dependency on `moc` when using the sysroot. +- sources += [ "qt_shim_moc.cc" ] +- } else { +- sources += get_target_outputs(":generate_moc") +- deps += [ ":generate_moc" ] ++ shared_library(target_name) { ++ visibility = [ ++ ":qt", ++ "//chrome/installer/linux:*", ++ ] ++ ++ # Since qt_shim is a shared library even in non-component builds, it shouldn't ++ # depend on any other targets since that would duplicate code between binaries ++ # leading to increased size and potential issues from duplicated global state. ++ no_default_deps = true ++ assert_no_deps = [ ++ "//base", ++ "//buildtools/third_party/libc++", ++ ] ++ deps = [ ":qt_interface" ] ++ ++ configs -= [ "//build/config/compiler:runtime_library" ] ++ configs += [ ++ ":qt_internal_config", ++ ":qt" + invoker.qt_version + "_config", ++ ] ++ ++ public = [] ++ sources = [ ++ "qt_shim.cc", ++ "qt_shim.h", ++ ] ++ if (use_sysroot) { ++ # This file is generated with gen_qt_shim_moc.sh on an amd64 system to ++ # avoid a build-time dependency on `moc` when using the sysroot. ++ sources += [ "qt" + invoker.qt_version + "_shim_moc.cc" ] ++ } else { ++ sources += get_target_outputs(":generate_moc") ++ deps += [ ":generate_moc" ] ++ } ++ } ++} ++qt_shim("qt5_shim") { ++ qt_version = "5" ++} ++if (use_qt6) { ++ qt_shim("qt6_shim") { ++ qt_version = "6" + } + } + +@@ -100,6 +110,9 @@ component("qt") { + + # qt_shim is in data_deps since we want to load it manually. + data_deps = [ ":qt5_shim" ] ++ if (use_qt6) { ++ data_deps += [ ":qt6_shim" ] ++ } + deps = [ + ":qt_interface", + "//base", +diff --git a/ui/qt/gen_qt_shim_moc.sh b/ui/qt/gen_qt_shim_moc.sh +index 74272d5611dab..9d02c2dfcb12f 100755 +--- a/ui/qt/gen_qt_shim_moc.sh ++++ b/ui/qt/gen_qt_shim_moc.sh +@@ -6,11 +6,15 @@ + set -o nounset + set -o errexit + +-URL="http://archive.debian.org/debian/pool/main/q/qtbase-opensource-src" +-PACKAGE="qtbase5-dev-tools_5.3.2+dfsg-4+deb8u2_amd64.deb" +-SHA256="7703754f2c230ce6b8b6030b6c1e7e030899aa9f45a415498df04bd5ec061a76" +-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ++URL5="http://archive.debian.org/debian/pool/main/q/qtbase-opensource-src" ++PACKAGE5="qtbase5-dev-tools_5.3.2+dfsg-4+deb8u2_amd64.deb" ++SHA256_5="7703754f2c230ce6b8b6030b6c1e7e030899aa9f45a415498df04bd5ec061a76" ++ ++URL6="http://archive.ubuntu.com/ubuntu/pool/universe/q/qt6-base" ++PACKAGE6="qt6-base-dev-tools_6.2.4+dfsg-2ubuntu1_amd64.deb" ++SHA256_6="8dddfc79e7743185b07c478ca0f96a4ccc13d48ecccc42f44d2578c33c7d9b8b" + ++SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + TMP_DIR=$(mktemp -d -p "$SCRIPT_DIR") + function cleanup { + rm -rf "$TMP_DIR" +@@ -18,16 +22,22 @@ function cleanup { + trap cleanup EXIT + + cd "$TMP_DIR" +-wget "$URL/$PACKAGE" +-echo "$SHA256 $PACKAGE" | shasum -a 256 -c +-dpkg -x "$PACKAGE" . +-cat > ../qt_shim_moc.cc < ../qt5_shim_moc.cc <> ui/qt/qt_shim_moc.cc +-git cl format ui/qt/qt_shim_moc.cc ++ >> ui/qt/qt5_shim_moc.cc ++"$TMP_DIR//usr/lib/qt6/libexec/moc" ui/qt/qt_shim.h \ ++ >> ui/qt/qt6_shim_moc.cc ++git cl format ui/qt/qt5_shim_moc.cc ui/qt/qt6_shim_moc.cc +diff --git a/ui/qt/qt.gni b/ui/qt/qt.gni +index 27bb6375880b7..f45823270cb91 100644 +--- a/ui/qt/qt.gni ++++ b/ui/qt/qt.gni +@@ -4,9 +4,17 @@ + + import("//build/config/chromecast_build.gni") + import("//build/config/sanitizers/sanitizers.gni") ++import("//build/config/sysroot.gni") + + declare_args() { + # TODO(https://crbug.com/1424435): Allow QT in MSAN builds once QT is + # added to the instrumented libraries. + use_qt = is_linux && !is_castos && !is_msan + } ++ ++declare_args() { ++ use_qt6 = use_qt && use_sysroot ++} ++ ++# use_qt6 => use_qt ++assert(!use_qt6 || use_qt) +diff --git a/ui/qt/qt_shim_moc.cc b/ui/qt/qt5_shim_moc.cc +similarity index 95% +rename from ui/qt/qt_shim_moc.cc +rename to ui/qt/qt5_shim_moc.cc +index dafbfadce56ba..8f8b6b57784a8 100644 +--- a/ui/qt/qt_shim_moc.cc ++++ b/ui/qt/qt5_shim_moc.cc +@@ -1,4 +1,4 @@ +-// Copyright 2022 The Chromium Authors ++// Copyright 2023 The Chromium Authors + // Use of this source code is governed by a BSD-style license that can be + // found in the LICENSE file. + +@@ -89,26 +89,32 @@ const QMetaObject* qt::QtShim::metaObject() const { + } + + void* qt::QtShim::qt_metacast(const char* _clname) { +- if (!_clname) ++ if (!_clname) { + return 0; +- if (!strcmp(_clname, qt_meta_stringdata_qt__QtShim.stringdata)) ++ } ++ if (!strcmp(_clname, qt_meta_stringdata_qt__QtShim.stringdata)) { + return static_cast(const_cast(this)); +- if (!strcmp(_clname, "QtInterface")) ++ } ++ if (!strcmp(_clname, "QtInterface")) { + return static_cast(const_cast(this)); ++ } + return QObject::qt_metacast(_clname); + } + + int qt::QtShim::qt_metacall(QMetaObject::Call _c, int _id, void** _a) { + _id = QObject::qt_metacall(_c, _id, _a); +- if (_id < 0) ++ if (_id < 0) { + return _id; ++ } + if (_c == QMetaObject::InvokeMetaMethod) { +- if (_id < 2) ++ if (_id < 2) { + qt_static_metacall(this, _c, _id, _a); ++ } + _id -= 2; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { +- if (_id < 2) ++ if (_id < 2) { + *reinterpret_cast(_a[0]) = -1; ++ } + _id -= 2; + } + return _id; +diff --git a/ui/qt/qt6_shim_moc.cc b/ui/qt/qt6_shim_moc.cc +new file mode 100644 +index 0000000000000..6d02ca317b65d +--- /dev/null ++++ b/ui/qt/qt6_shim_moc.cc +@@ -0,0 +1,143 @@ ++// Copyright 2023 The Chromium Authors ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++/**************************************************************************** ++** Meta object code from reading C++ file 'qt_shim.h' ++** ++** Created by: The Qt Meta Object Compiler version 68 (Qt 6.2.4) ++** ++** WARNING! All changes made in this file will be lost! ++*****************************************************************************/ ++ ++#include ++#include ++#include ++#include "ui/qt/qt_shim.h" ++#if !defined(Q_MOC_OUTPUT_REVISION) ++#error "The header file 'qt_shim.h' doesn't include ." ++#elif Q_MOC_OUTPUT_REVISION != 68 ++#error "This file was generated using the moc from 6.2.4. It" ++#error "cannot be used with the include files from this version of Qt." ++#error "(The moc has changed too much.)" ++#endif ++ ++QT_BEGIN_MOC_NAMESPACE ++QT_WARNING_PUSH ++QT_WARNING_DISABLE_DEPRECATED ++struct qt_meta_stringdata_qt__QtShim_t { ++ const uint offsetsAndSize[12]; ++ char stringdata0[52]; ++}; ++#define QT_MOC_LITERAL(ofs, len) \ ++ uint(offsetof(qt_meta_stringdata_qt__QtShim_t, stringdata0) + ofs), len ++static const qt_meta_stringdata_qt__QtShim_t qt_meta_stringdata_qt__QtShim = { ++ { ++ QT_MOC_LITERAL(0, 10), // "qt::QtShim" ++ QT_MOC_LITERAL(11, 11), // "FontChanged" ++ QT_MOC_LITERAL(23, 0), // "" ++ QT_MOC_LITERAL(24, 4), // "font" ++ QT_MOC_LITERAL(29, 14), // "PaletteChanged" ++ QT_MOC_LITERAL(44, 7) // "palette" ++ ++ }, ++ "qt::QtShim\0FontChanged\0\0font\0" ++ "PaletteChanged\0palette"}; ++#undef QT_MOC_LITERAL ++ ++static const uint qt_meta_data_qt__QtShim[] = { ++ ++ // content: ++ 10, // revision ++ 0, // classname ++ 0, 0, // classinfo ++ 2, 14, // methods ++ 0, 0, // properties ++ 0, 0, // enums/sets ++ 0, 0, // constructors ++ 0, // flags ++ 0, // signalCount ++ ++ // slots: name, argc, parameters, tag, flags, initial metatype offsets ++ 1, 1, 26, 2, 0x08, 1 /* Private */, 4, 1, 29, 2, 0x08, 3 /* Private */, ++ ++ // slots: parameters ++ QMetaType::Void, QMetaType::QFont, 3, QMetaType::Void, QMetaType::QPalette, ++ 5, ++ ++ 0 // eod ++}; ++ ++void qt::QtShim::qt_static_metacall(QObject* _o, ++ QMetaObject::Call _c, ++ int _id, ++ void** _a) { ++ if (_c == QMetaObject::InvokeMetaMethod) { ++ auto* _t = static_cast(_o); ++ (void)_t; ++ switch (_id) { ++ case 0: ++ _t->FontChanged((*reinterpret_cast>(_a[1]))); ++ break; ++ case 1: ++ _t->PaletteChanged( ++ (*reinterpret_cast>(_a[1]))); ++ break; ++ default:; ++ } ++ } ++} ++ ++const QMetaObject qt::QtShim::staticMetaObject = { ++ {QMetaObject::SuperData::link(), ++ qt_meta_stringdata_qt__QtShim.offsetsAndSize, qt_meta_data_qt__QtShim, ++ qt_static_metacall, nullptr, ++ qt_incomplete_metaTypeArray< ++ qt_meta_stringdata_qt__QtShim_t, ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete ++ ++ >, ++ nullptr}}; ++ ++const QMetaObject* qt::QtShim::metaObject() const { ++ return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() ++ : &staticMetaObject; ++} ++ ++void* qt::QtShim::qt_metacast(const char* _clname) { ++ if (!_clname) { ++ return nullptr; ++ } ++ if (!strcmp(_clname, qt_meta_stringdata_qt__QtShim.stringdata0)) { ++ return static_cast(this); ++ } ++ if (!strcmp(_clname, "QtInterface")) { ++ return static_cast(this); ++ } ++ return QObject::qt_metacast(_clname); ++} ++ ++int qt::QtShim::qt_metacall(QMetaObject::Call _c, int _id, void** _a) { ++ _id = QObject::qt_metacall(_c, _id, _a); ++ if (_id < 0) { ++ return _id; ++ } ++ if (_c == QMetaObject::InvokeMetaMethod) { ++ if (_id < 2) { ++ qt_static_metacall(this, _c, _id, _a); ++ } ++ _id -= 2; ++ } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { ++ if (_id < 2) { ++ *reinterpret_cast(_a[0]) = QMetaType(); ++ } ++ _id -= 2; ++ } ++ return _id; ++} ++QT_WARNING_POP ++QT_END_MOC_NAMESPACE +diff --git a/ui/qt/qt_ui.cc b/ui/qt/qt_ui.cc +index d4052b7e8bc3d..6a3b58e9f930b 100644 +--- a/ui/qt/qt_ui.cc ++++ b/ui/qt/qt_ui.cc +@@ -14,7 +14,9 @@ + #include "base/check.h" + #include "base/command_line.h" + #include "base/compiler_specific.h" ++#include "base/environment.h" + #include "base/memory/raw_ptr.h" ++#include "base/nix/xdg_util.h" + #include "base/notreached.h" + #include "base/path_service.h" + #include "base/time/time.h" +@@ -47,6 +49,45 @@ namespace qt { + + namespace { + ++const char kQtVersionFlag[] = "qt-version"; ++ ++void* LoadLibrary(const base::FilePath& path) { ++ return dlopen(path.value().c_str(), RTLD_NOW | RTLD_GLOBAL); ++} ++ ++void* LoadLibraryOrFallback(const base::FilePath& path, ++ const char* preferred, ++ const char* fallback) { ++ if (void* library = LoadLibrary(path.Append(preferred))) { ++ return library; ++ } ++ return LoadLibrary(path.Append(fallback)); ++} ++ ++bool PreferQt6() { ++ auto* cmd = base::CommandLine::ForCurrentProcess(); ++ if (cmd->HasSwitch(kQtVersionFlag)) { ++ std::string qt_version_string = cmd->GetSwitchValueASCII(kQtVersionFlag); ++ unsigned int qt_version = 0; ++ if (base::StringToUint(qt_version_string, &qt_version)) { ++ switch (qt_version) { ++ case 5: ++ return false; ++ case 6: ++ return true; ++ default: ++ LOG(ERROR) << "Unsupported QT version " << qt_version; ++ } ++ } else { ++ LOG(ERROR) << "Unable to parse QT version " << qt_version_string; ++ } ++ } ++ ++ auto env = base::Environment::Create(); ++ auto desktop = base::nix::GetDesktopEnvironment(env.get()); ++ return desktop == base::nix::DESKTOP_ENVIRONMENT_KDE6; ++} ++ + int QtWeightToCssWeight(int weight) { + struct { + int qt_weight; +@@ -179,8 +220,10 @@ bool QtUi::Initialize() { + base::FilePath path; + if (!base::PathService::Get(base::DIR_MODULE, &path)) + return false; +- path = path.Append("libqt5_shim.so"); +- void* libqt_shim = dlopen(path.value().c_str(), RTLD_NOW | RTLD_GLOBAL); ++ void* libqt_shim = ++ PreferQt6() ++ ? LoadLibraryOrFallback(path, "libqt6_shim.so", "libqt5_shim.so") ++ : LoadLibraryOrFallback(path, "libqt5_shim.so", "libqt6_shim.so"); + if (!libqt_shim) + return false; + void* create_qt_interface = dlsym(libqt_shim, "CreateQtInterface"); diff --git a/chromium-114-qt-fix_font_double_scaling.patch b/chromium-114-qt-fix_font_double_scaling.patch new file mode 100644 index 00000000..9713ef63 --- /dev/null +++ b/chromium-114-qt-fix_font_double_scaling.patch @@ -0,0 +1,21 @@ +diff --git a/ui/qt/qt_ui.cc b/ui/qt/qt_ui.cc +index bac5245a..a97fa8b 100644 +--- a/ui/qt/qt_ui.cc ++++ b/ui/qt/qt_ui.cc +@@ -422,12 +422,14 @@ + auto desc = shim_->GetFontDescription(); + + font_family_ = desc.family.c_str(); ++ // Points are defined at 72 DPI and pixels are 96 DPI by default. ++ constexpr double kPointToPixelRatio = 96.0 / 72.0; + if (desc.size_pixels > 0) { + font_size_pixels_ = desc.size_pixels; +- font_size_points_ = font_size_pixels_ / GetDeviceScaleFactor(); ++ font_size_points_ = std::round(font_size_pixels_ / kPointToPixelRatio); + } else { + font_size_points_ = desc.size_points; +- font_size_pixels_ = font_size_points_ * GetDeviceScaleFactor(); ++ font_size_pixels_ = std::round(font_size_points_ * kPointToPixelRatio); + } + font_style_ = desc.is_italic ? gfx::Font::ITALIC : gfx::Font::NORMAL; + font_weight_ = QtWeightToCssWeight(desc.weight); diff --git a/chromium-114-qt-handle_scale_factor_changes.patch b/chromium-114-qt-handle_scale_factor_changes.patch new file mode 100644 index 00000000..d8fc72fd --- /dev/null +++ b/chromium-114-qt-handle_scale_factor_changes.patch @@ -0,0 +1,574 @@ +commit c51d6447fd0d124903d16bf5952efccbf9e1ca92 +Author: Tom Anderson +Date: Wed May 24 22:53:20 2023 +0000 + + [Qt] Handle scale factor changes + + This is a speculative fix for https://crbug.com/1439149. I suspect + the scale factor is not set immediately on QT initialization, but + is set asynchronously shortly after. This CL adds a listener for + QT scale changes. + + R=thestig + + Low-Coverage-Reason: No QT tests currently + Change-Id: I7dea23e16a6bb26237564af2dc4e43480f6aea9f + Bug: 1439149 + Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4559732 + Reviewed-by: Lei Zhang + Commit-Queue: Thomas Anderson + Auto-Submit: Thomas Anderson + Cr-Commit-Position: refs/heads/main@{#1148805} + +diff --git a/ui/qt/qt5_shim_moc.cc b/ui/qt/qt5_shim_moc.cc +index 8f8b6b57784a8..6e504f23c603a 100644 +--- a/ui/qt/qt5_shim_moc.cc ++++ b/ui/qt/qt5_shim_moc.cc +@@ -23,8 +23,8 @@ + + QT_BEGIN_MOC_NAMESPACE + struct qt_meta_stringdata_qt__QtShim_t { +- QByteArrayData data[6]; +- char stringdata[52]; ++ QByteArrayData data[13]; ++ char stringdata[151]; + }; + #define QT_MOC_LITERAL(idx, ofs, len) \ + Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET( \ +@@ -33,9 +33,16 @@ struct qt_meta_stringdata_qt__QtShim_t { + static const qt_meta_stringdata_qt__QtShim_t qt_meta_stringdata_qt__QtShim = { + {QT_MOC_LITERAL(0, 0, 10), QT_MOC_LITERAL(1, 11, 11), + QT_MOC_LITERAL(2, 23, 0), QT_MOC_LITERAL(3, 24, 4), +- QT_MOC_LITERAL(4, 29, 14), QT_MOC_LITERAL(5, 44, 7)}, ++ QT_MOC_LITERAL(4, 29, 14), QT_MOC_LITERAL(5, 44, 7), ++ QT_MOC_LITERAL(6, 52, 11), QT_MOC_LITERAL(7, 64, 8), ++ QT_MOC_LITERAL(8, 73, 6), QT_MOC_LITERAL(9, 80, 13), ++ QT_MOC_LITERAL(10, 94, 25), QT_MOC_LITERAL(11, 120, 3), ++ QT_MOC_LITERAL(12, 124, 26)}, + "qt::QtShim\0FontChanged\0\0font\0" +- "PaletteChanged\0palette"}; ++ "PaletteChanged\0palette\0ScreenAdded\0" ++ "QScreen*\0screen\0ScreenRemoved\0" ++ "LogicalDotsPerInchChanged\0dpi\0" ++ "PhysicalDotsPerInchChanged"}; + #undef QT_MOC_LITERAL + + static const uint qt_meta_data_qt__QtShim[] = { +@@ -44,7 +51,7 @@ static const uint qt_meta_data_qt__QtShim[] = { + 7, // revision + 0, // classname + 0, 0, // classinfo +- 2, 14, // methods ++ 6, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors +@@ -52,11 +59,15 @@ static const uint qt_meta_data_qt__QtShim[] = { + 0, // signalCount + + // slots: name, argc, parameters, tag, flags +- 1, 1, 24, 2, 0x08 /* Private */, 4, 1, 27, 2, 0x08 /* Private */, ++ 1, 1, 44, 2, 0x08 /* Private */, 4, 1, 47, 2, 0x08 /* Private */, 6, 1, 50, ++ 2, 0x08 /* Private */, 9, 1, 53, 2, 0x08 /* Private */, 10, 1, 56, 2, ++ 0x08 /* Private */, 12, 1, 59, 2, 0x08 /* Private */, + + // slots: parameters + QMetaType::Void, QMetaType::QFont, 3, QMetaType::Void, QMetaType::QPalette, +- 5, ++ 5, QMetaType::Void, 0x80000000 | 7, 8, QMetaType::Void, 0x80000000 | 7, 8, ++ QMetaType::Void, QMetaType::QReal, 11, QMetaType::Void, QMetaType::QReal, ++ 11, + + 0 // eod + }; +@@ -74,6 +85,18 @@ void qt::QtShim::qt_static_metacall(QObject* _o, + case 1: + _t->PaletteChanged((*reinterpret_cast(_a[1]))); + break; ++ case 2: ++ _t->ScreenAdded((*reinterpret_cast(_a[1]))); ++ break; ++ case 3: ++ _t->ScreenRemoved((*reinterpret_cast(_a[1]))); ++ break; ++ case 4: ++ _t->LogicalDotsPerInchChanged((*reinterpret_cast(_a[1]))); ++ break; ++ case 5: ++ _t->PhysicalDotsPerInchChanged((*reinterpret_cast(_a[1]))); ++ break; + default:; + } + } +@@ -107,15 +130,15 @@ int qt::QtShim::qt_metacall(QMetaObject::Call _c, int _id, void** _a) { + return _id; + } + if (_c == QMetaObject::InvokeMetaMethod) { +- if (_id < 2) { ++ if (_id < 6) { + qt_static_metacall(this, _c, _id, _a); + } +- _id -= 2; ++ _id -= 6; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { +- if (_id < 2) { ++ if (_id < 6) { + *reinterpret_cast(_a[0]) = -1; + } +- _id -= 2; ++ _id -= 6; + } + return _id; + } +diff --git a/ui/qt/qt6_shim_moc.cc b/ui/qt/qt6_shim_moc.cc +index 6d02ca317b65d..a16515008d892 100644 +--- a/ui/qt/qt6_shim_moc.cc ++++ b/ui/qt/qt6_shim_moc.cc +@@ -26,8 +26,8 @@ QT_BEGIN_MOC_NAMESPACE + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED + struct qt_meta_stringdata_qt__QtShim_t { +- const uint offsetsAndSize[12]; +- char stringdata0[52]; ++ const uint offsetsAndSize[26]; ++ char stringdata0[151]; + }; + #define QT_MOC_LITERAL(ofs, len) \ + uint(offsetof(qt_meta_stringdata_qt__QtShim_t, stringdata0) + ofs), len +@@ -38,11 +38,21 @@ static const qt_meta_stringdata_qt__QtShim_t qt_meta_stringdata_qt__QtShim = { + QT_MOC_LITERAL(23, 0), // "" + QT_MOC_LITERAL(24, 4), // "font" + QT_MOC_LITERAL(29, 14), // "PaletteChanged" +- QT_MOC_LITERAL(44, 7) // "palette" ++ QT_MOC_LITERAL(44, 7), // "palette" ++ QT_MOC_LITERAL(52, 11), // "ScreenAdded" ++ QT_MOC_LITERAL(64, 8), // "QScreen*" ++ QT_MOC_LITERAL(73, 6), // "screen" ++ QT_MOC_LITERAL(80, 13), // "ScreenRemoved" ++ QT_MOC_LITERAL(94, 25), // "LogicalDotsPerInchChanged" ++ QT_MOC_LITERAL(120, 3), // "dpi" ++ QT_MOC_LITERAL(124, 26) // "PhysicalDotsPerInchChanged" + + }, + "qt::QtShim\0FontChanged\0\0font\0" +- "PaletteChanged\0palette"}; ++ "PaletteChanged\0palette\0ScreenAdded\0" ++ "QScreen*\0screen\0ScreenRemoved\0" ++ "LogicalDotsPerInchChanged\0dpi\0" ++ "PhysicalDotsPerInchChanged"}; + #undef QT_MOC_LITERAL + + static const uint qt_meta_data_qt__QtShim[] = { +@@ -51,7 +61,7 @@ static const uint qt_meta_data_qt__QtShim[] = { + 10, // revision + 0, // classname + 0, 0, // classinfo +- 2, 14, // methods ++ 6, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors +@@ -59,11 +69,15 @@ static const uint qt_meta_data_qt__QtShim[] = { + 0, // signalCount + + // slots: name, argc, parameters, tag, flags, initial metatype offsets +- 1, 1, 26, 2, 0x08, 1 /* Private */, 4, 1, 29, 2, 0x08, 3 /* Private */, ++ 1, 1, 50, 2, 0x08, 1 /* Private */, 4, 1, 53, 2, 0x08, 3 /* Private */, 6, ++ 1, 56, 2, 0x08, 5 /* Private */, 9, 1, 59, 2, 0x08, 7 /* Private */, 10, 1, ++ 62, 2, 0x08, 9 /* Private */, 12, 1, 65, 2, 0x08, 11 /* Private */, + + // slots: parameters + QMetaType::Void, QMetaType::QFont, 3, QMetaType::Void, QMetaType::QPalette, +- 5, ++ 5, QMetaType::Void, 0x80000000 | 7, 8, QMetaType::Void, 0x80000000 | 7, 8, ++ QMetaType::Void, QMetaType::QReal, 11, QMetaType::Void, QMetaType::QReal, ++ 11, + + 0 // eod + }; +@@ -83,6 +97,22 @@ void qt::QtShim::qt_static_metacall(QObject* _o, + _t->PaletteChanged( + (*reinterpret_cast>(_a[1]))); + break; ++ case 2: ++ _t->ScreenAdded( ++ (*reinterpret_cast>(_a[1]))); ++ break; ++ case 3: ++ _t->ScreenRemoved( ++ (*reinterpret_cast>(_a[1]))); ++ break; ++ case 4: ++ _t->LogicalDotsPerInchChanged( ++ (*reinterpret_cast>(_a[1]))); ++ break; ++ case 5: ++ _t->PhysicalDotsPerInchChanged( ++ (*reinterpret_cast>(_a[1]))); ++ break; + default:; + } + } +@@ -98,7 +128,15 @@ const QMetaObject qt::QtShim::staticMetaObject = { + QtPrivate::TypeAndForceComplete, + QtPrivate::TypeAndForceComplete, + QtPrivate::TypeAndForceComplete, +- QtPrivate::TypeAndForceComplete ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete, ++ QtPrivate::TypeAndForceComplete + + >, + nullptr}}; +@@ -127,15 +165,15 @@ int qt::QtShim::qt_metacall(QMetaObject::Call _c, int _id, void** _a) { + return _id; + } + if (_c == QMetaObject::InvokeMetaMethod) { +- if (_id < 2) { ++ if (_id < 6) { + qt_static_metacall(this, _c, _id, _a); + } +- _id -= 2; ++ _id -= 6; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { +- if (_id < 2) { ++ if (_id < 6) { + *reinterpret_cast(_a[0]) = QMetaType(); + } +- _id -= 2; ++ _id -= 6; + } + return _id; + } +diff --git a/ui/qt/qt_interface.h b/ui/qt/qt_interface.h +index 6a362bc66c0e3..28dfc6603544f 100644 +--- a/ui/qt/qt_interface.h ++++ b/ui/qt/qt_interface.h +@@ -118,6 +118,7 @@ class QtInterface { + + virtual void FontChanged() = 0; + virtual void ThemeChanged() = 0; ++ virtual void ScaleFactorMaybeChanged() = 0; + }; + + QtInterface() = default; +diff --git a/ui/qt/qt_shim.cc b/ui/qt/qt_shim.cc +index 74d34ad196f18..0aec9c3aed4ad 100644 +--- a/ui/qt/qt_shim.cc ++++ b/ui/qt/qt_shim.cc +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -52,8 +53,9 @@ FontHinting QtHintingToFontHinting(QFont::HintingPreference hinting) { + // Obtain the average color of a gradient. + SkColor GradientColor(const QGradient& gradient) { + QGradientStops stops = gradient.stops(); +- if (stops.empty()) ++ if (stops.empty()) { + return qRgba(0, 0, 0, 0); ++ } + + float a = 0; + float r = 0; +@@ -86,11 +88,13 @@ SkColor GradientColor(const QGradient& gradient) { + // Obtain the average color of a texture. + SkColor TextureColor(QImage image) { + size_t size = image.width() * image.height(); +- if (!size) ++ if (!size) { + return qRgba(0, 0, 0, 0); ++ } + +- if (image.format() != QImage::Format_ARGB32_Premultiplied) ++ if (image.format() != QImage::Format_ARGB32_Premultiplied) { + image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); ++ } + + size_t a = 0; + size_t r = 0; +@@ -203,6 +207,13 @@ QtShim::QtShim(QtInterface::Delegate* delegate, int* argc, char** argv) + SLOT(FontChanged(const QFont&))); + connect(&app_, SIGNAL(paletteChanged(const QPalette&)), this, + SLOT(PaletteChanged(const QPalette&))); ++ connect(&app_, SIGNAL(screenAdded(QScreen*)), this, ++ SLOT(ScreenAdded(QScreen*))); ++ connect(&app_, SIGNAL(screenRemoved(QScreen*)), this, ++ SLOT(ScreenRemoved(QScreen*))); ++ for (QScreen* screen : app_.screens()) { ++ ScreenAdded(screen); ++ } + } + + QtShim::~QtShim() = default; +@@ -241,8 +252,9 @@ Image QtShim::GetIconForContentType(const String& content_type, + auto icon = QIcon::fromTheme(name); + auto pixmap = icon.pixmap(size); + auto image = pixmap.toImage(); +- if (image.format() != QImage::Format_ARGB32_Premultiplied) ++ if (image.format() != QImage::Format_ARGB32_Premultiplied) { + image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); ++ } + if (auto bytes = image.sizeInBytes()) { + return {image.width(), image.height(), + static_cast(image.devicePixelRatio()), +@@ -283,6 +295,30 @@ void QtShim::PaletteChanged(const QPalette& palette) { + delegate_->ThemeChanged(); + } + ++DISABLE_CFI_VCALL ++void QtShim::ScreenAdded(QScreen* screen) { ++ connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)), this, ++ SLOT(LogicalDotsPerInchChanged(qreal))); ++ connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)), this, ++ SLOT(PhysicalDotsPerInchChanged(qreal))); ++ delegate_->ScaleFactorMaybeChanged(); ++} ++ ++DISABLE_CFI_VCALL ++void QtShim::ScreenRemoved(QScreen* screen) { ++ delegate_->ScaleFactorMaybeChanged(); ++} ++ ++DISABLE_CFI_VCALL ++void QtShim::LogicalDotsPerInchChanged(qreal dpi) { ++ delegate_->ScaleFactorMaybeChanged(); ++} ++ ++DISABLE_CFI_VCALL ++void QtShim::PhysicalDotsPerInchChanged(qreal dpi) { ++ delegate_->ScaleFactorMaybeChanged(); ++} ++ + Image QtShim::DrawHeader(int width, + int height, + SkColor default_color, +@@ -309,8 +345,9 @@ QImage QtShim::DrawHeaderImpl(int width, + QStyleOptionTitleBar opt; + opt.rect = QRect(-kBorderWidth, -kBorderWidth, width + 2 * kBorderWidth, + height + 2 * kBorderWidth); +- if (state == ColorState::kNormal) ++ if (state == ColorState::kNormal) { + opt.titleBarState = QStyle::State_Active; ++ } + app_.style()->drawComplexControl(QStyle::CC_TitleBar, &opt, &painter, + nullptr); + } else { +diff --git a/ui/qt/qt_shim.h b/ui/qt/qt_shim.h +index 607e6fe22dfc0..d979c47d589d4 100644 +--- a/ui/qt/qt_shim.h ++++ b/ui/qt/qt_shim.h +@@ -42,6 +42,10 @@ class QtShim : public QObject, public QtInterface { + private slots: + void FontChanged(const QFont& font); + void PaletteChanged(const QPalette& palette); ++ void ScreenAdded(QScreen* screen); ++ void ScreenRemoved(QScreen* screen); ++ void LogicalDotsPerInchChanged(qreal dpi); ++ void PhysicalDotsPerInchChanged(qreal dpi); + + private: + QImage DrawHeaderImpl(int width, +diff --git a/ui/qt/qt_ui.cc b/ui/qt/qt_ui.cc +index 6a3b58e9f930b..bac5245a069f9 100644 +--- a/ui/qt/qt_ui.cc ++++ b/ui/qt/qt_ui.cc +@@ -19,6 +19,7 @@ + #include "base/nix/xdg_util.h" + #include "base/notreached.h" + #include "base/path_service.h" ++#include "base/task/single_thread_task_runner.h" + #include "base/time/time.h" + #include "cc/paint/paint_canvas.h" + #include "chrome/browser/themes/theme_properties.h" // nogncheck +@@ -36,6 +37,7 @@ + #include "ui/gfx/image/image.h" + #include "ui/gfx/image/image_skia_rep.h" + #include "ui/gfx/image/image_skia_source.h" ++#include "ui/linux/device_scale_factor_observer.h" + #include "ui/linux/linux_ui.h" + #include "ui/linux/nav_button_provider.h" + #include "ui/native_theme/native_theme_aura.h" +@@ -194,16 +196,21 @@ void QtUi::GetDefaultFontDescription(std::string* family_out, + int* style_out, + int* weight_out, + gfx::FontRenderParams* params_out) const { +- if (family_out) ++ if (family_out) { + *family_out = font_family_; +- if (size_pixels_out) ++ } ++ if (size_pixels_out) { + *size_pixels_out = font_size_pixels_; +- if (style_out) ++ } ++ if (style_out) { + *style_out = font_style_; +- if (weight_out) ++ } ++ if (weight_out) { + *weight_out = font_weight_; +- if (params_out) ++ } ++ if (params_out) { + *params_out = font_params_; ++ } + } + + ui::SelectFileDialog* QtUi::CreateSelectFileDialog( +@@ -236,6 +245,7 @@ bool QtUi::Initialize() { + ui::ColorProviderManager::Get().AppendColorProviderInitializer( + base::BindRepeating(&QtUi::AddNativeColorMixer, base::Unretained(this))); + FontChanged(); ++ scale_factor_ = shim_->GetScaleFactor(); + + return true; + } +@@ -246,8 +256,9 @@ ui::NativeTheme* QtUi::GetNativeTheme() const { + + bool QtUi::GetColor(int id, SkColor* color, bool use_custom_frame) const { + auto value = GetColor(id, use_custom_frame); +- if (value) ++ if (value) { + *color = *value; ++ } + return value.has_value(); + } + +@@ -297,8 +308,9 @@ gfx::Image QtUi::GetIconForContentType(const std::string& content_type, + float scale) const { + Image image = + shim_->GetIconForContentType(String(content_type.c_str()), size * scale); +- if (!image.data_argb.size()) ++ if (!image.data_argb.size()) { + return {}; ++ } + + SkImageInfo image_info = SkImageInfo::Make( + image.width, image.height, kBGRA_8888_SkColorType, kPremul_SkAlphaType); +@@ -345,14 +357,16 @@ bool QtUi::AnimationsEnabled() const { + + void QtUi::AddWindowButtonOrderObserver( + ui::WindowButtonOrderObserver* observer) { +- if (fallback_linux_ui_) ++ if (fallback_linux_ui_) { + fallback_linux_ui_->AddWindowButtonOrderObserver(observer); ++ } + } + + void QtUi::RemoveWindowButtonOrderObserver( + ui::WindowButtonOrderObserver* observer) { +- if (fallback_linux_ui_) ++ if (fallback_linux_ui_) { + fallback_linux_ui_->RemoveWindowButtonOrderObserver(observer); ++ } + } + + std::unique_ptr QtUi::CreateNavButtonProvider() { +@@ -441,11 +455,24 @@ void QtUi::ThemeChanged() { + native_theme_->ThemeChanged(PreferDarkTheme()); + } + ++void QtUi::ScaleFactorMaybeChanged() { ++ // This gets called whenever the monitor configuration changes. Handle the ++ // scale change asynchronously to allow the change to propagate to QT's scale ++ // factor. This also coalesces scale change events together. ++ if (!scale_factor_task_active_) { ++ scale_factor_task_active_ = true; ++ base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( ++ FROM_HERE, base::BindOnce(&QtUi::ScaleFactorMaybeChangedImpl, ++ weak_factory_.GetWeakPtr())); ++ } ++} ++ + DISABLE_CFI_VCALL + void QtUi::AddNativeColorMixer(ui::ColorProvider* provider, + const ui::ColorProviderManager::Key& key) { +- if (key.system_theme != ui::SystemTheme::kQt) ++ if (key.system_theme != ui::SystemTheme::kQt) { + return; ++ } + + ui::ColorMixer& mixer = provider->AddMixer(); + // These color constants are required by native_chrome_color_mixer_linux.cc +@@ -494,8 +521,9 @@ void QtUi::AddNativeColorMixer(ui::ColorProvider* provider, + ColorState::kInactive}, + {ui::kColorNativeToolbarBackground, ColorType::kButtonBg}, + }; +- for (const auto& map : kMaps) ++ for (const auto& map : kMaps) { + mixer[map.id] = {shim_->GetColor(map.role, map.state)}; ++ } + + const bool use_custom_frame = + key.frame_type == ui::ColorProviderManager::FrameType::kChromium; +@@ -578,6 +606,20 @@ absl::optional QtUi::GetColor(int id, bool use_custom_frame) const { + } + } + ++DISABLE_CFI_VCALL ++void QtUi::ScaleFactorMaybeChangedImpl() { ++ scale_factor_task_active_ = false; ++ double scale = shim_->GetScaleFactor(); ++ if (scale == scale_factor_) { ++ return; ++ } ++ scale_factor_ = scale; ++ for (ui::DeviceScaleFactorObserver& observer : ++ device_scale_factor_observer_list()) { ++ observer.OnDeviceScaleFactorChanged(); ++ } ++} ++ + std::unique_ptr CreateQtUi( + ui::LinuxUi* fallback_linux_ui) { + return std::make_unique(fallback_linux_ui); +diff --git a/ui/qt/qt_ui.h b/ui/qt/qt_ui.h +index b53ed93240708..3319edf1ea9bc 100644 +--- a/ui/qt/qt_ui.h ++++ b/ui/qt/qt_ui.h +@@ -8,6 +8,7 @@ + #include + + #include "base/component_export.h" ++#include "base/memory/weak_ptr.h" + #include "printing/buildflags/buildflags.h" + #include "third_party/abseil-cpp/absl/types/optional.h" + #include "ui/color/color_provider.h" +@@ -88,11 +89,14 @@ class QtUi : public ui::LinuxUiAndTheme, QtInterface::Delegate { + // QtInterface::Delegate: + void FontChanged() override; + void ThemeChanged() override; ++ void ScaleFactorMaybeChanged() override; + + private: + void AddNativeColorMixer(ui::ColorProvider* provider, + const ui::ColorProviderManager::Key& key); + ++ void ScaleFactorMaybeChangedImpl(); ++ + absl::optional GetColor(int id, bool use_custom_frame) const; + + // TODO(https://crbug.com/1317782): This is a fallback for any unimplemented +@@ -114,6 +118,11 @@ class QtUi : public ui::LinuxUiAndTheme, QtInterface::Delegate { + std::unique_ptr shim_; + + std::unique_ptr native_theme_; ++ ++ bool scale_factor_task_active_ = false; ++ double scale_factor_ = 1.0; ++ ++ base::WeakPtrFactory weak_factory_{this}; + }; + + // This should be the only symbol exported from this component. diff --git a/chromium.spec b/chromium.spec index c876a9b8..3db1e96c 100644 --- a/chromium.spec +++ b/chromium.spec @@ -21,7 +21,7 @@ # This flag is so I can build things very fast on a giant system. # Enabling this in koji causes aarch64 builds to timeout indefinitely. -%global use_all_cpus 1 +%global use_all_cpus 0 %if %{use_all_cpus} %global numjobs %{_smp_build_ncpus} @@ -360,6 +360,10 @@ Patch300: chromium-113-rhel8-force-disable-use_gnome_keyring.patch Patch302: chromium-114-workaround_clang_bug-structured_binding.patch # missing typename Patch303: chromium-114-typename.patch +# Qt issue +Patch320: chromium-114-add_qt6_linuxui_backend.patch +Patch321: chromium-114-qt-handle_scale_factor_changes.patch +Patch322: chromium-114-qt-fix_font_double_scaling.patch # Use chromium-latest.py to generate clean tarball from released build tarballs, found here: # http://build.chromium.org/buildbot/official/ @@ -958,6 +962,10 @@ udev. %patch -P303 -p1 -b .typename +%patch -P320 -p1 -b .add_qt6_linuxui_backend +%patch -P321 -p1 -b .handle_scale_factor_changes +%patch -P322 -p1 -b .fix_font_double_scaling + # Change shebang in all relevant files in this directory and all subdirectories # See `man find` for how the `-exec command {} +` syntax works find -type f \( -iname "*.py" \) -exec sed -i '1s=^#! */usr/bin/\(python\|env python\)[23]\?=#!%{__python3}=' {} + @@ -1633,8 +1641,11 @@ getent group chrome-remote-desktop >/dev/null || groupadd -r chrome-remote-deskt %{chromium_path}/chromedriver %changelog -* Fri May 26 2023 Than Ngo - 114.0.5735.45-1 +* Sun May 28 2023 Than Ngo - 114.0.5735.45-1 - update to 114.0.5735.45 +- add qt6 linuxui backend +- backport: handle scale factor changes +- backport: fix font double_scaling * Wed May 17 2023 Than Ngo - 113.0.5672.126-1 - drop clang workaround for el8