From b4b98f0cf04a36845116bde4dd89f76bf55ec709 Mon Sep 17 00:00:00 2001
From: Britney Fransen <brfransen@gmail.com>
Date: Tue, 11 Nov 2025 16:19:20 -0500
Subject: qt5-webengine: initial inclusion

---
 linhes/qt5-webengine/.nvchecker.toml               |    6 +
 linhes/qt5-webengine/LICENSE                       |   12 +
 linhes/qt5-webengine/LICENSES/0BSD.txt             |    1 +
 linhes/qt5-webengine/LICENSES/BSD-3-Clause.txt     |   11 +
 linhes/qt5-webengine/PKGBUILD                      |   87 +
 linhes/qt5-webengine/README.md                     |    3 +
 linhes/qt5-webengine/REUSE.toml                    |   36 +
 linhes/qt5-webengine/python3.12-imp.patch          |   26 +
 linhes/qt5-webengine/python3.12-six.patch          |   58 +
 linhes/qt5-webengine/qt5-webengine-gcc-15.patch    |  443 +++++
 linhes/qt5-webengine/qt5-webengine-icu-75.patch    |   99 ++
 linhes/qt5-webengine/qt5-webengine-icu-78.patch    |   79 +
 .../qt5-webengine/qt5-webengine-ninja-1.12.patch   |   12 +
 .../qt5-webengine/qt5-webengine-pipewire-0.3.patch | 1819 ++++++++++++++++++++
 14 files changed, 2692 insertions(+)
 create mode 100644 linhes/qt5-webengine/.nvchecker.toml
 create mode 100644 linhes/qt5-webengine/LICENSE
 create mode 120000 linhes/qt5-webengine/LICENSES/0BSD.txt
 create mode 100644 linhes/qt5-webengine/LICENSES/BSD-3-Clause.txt
 create mode 100644 linhes/qt5-webengine/PKGBUILD
 create mode 100644 linhes/qt5-webengine/README.md
 create mode 100644 linhes/qt5-webengine/REUSE.toml
 create mode 100644 linhes/qt5-webengine/python3.12-imp.patch
 create mode 100644 linhes/qt5-webengine/python3.12-six.patch
 create mode 100644 linhes/qt5-webengine/qt5-webengine-gcc-15.patch
 create mode 100644 linhes/qt5-webengine/qt5-webengine-icu-75.patch
 create mode 100644 linhes/qt5-webengine/qt5-webengine-icu-78.patch
 create mode 100644 linhes/qt5-webengine/qt5-webengine-ninja-1.12.patch
 create mode 100644 linhes/qt5-webengine/qt5-webengine-pipewire-0.3.patch

diff --git a/linhes/qt5-webengine/.nvchecker.toml b/linhes/qt5-webengine/.nvchecker.toml
new file mode 100644
index 0000000..4960664
--- /dev/null
+++ b/linhes/qt5-webengine/.nvchecker.toml
@@ -0,0 +1,6 @@
+[qt5-webengine]
+source = 'git'
+git = 'git://code.qt.io/qt/qtwebengine.git'
+include_regex = 'v(\d.+)-lts'
+from_pattern = 'v(\d.+)-lts'
+to_pattern = '\1'
diff --git a/linhes/qt5-webengine/LICENSE b/linhes/qt5-webengine/LICENSE
new file mode 100644
index 0000000..b87c5e4
--- /dev/null
+++ b/linhes/qt5-webengine/LICENSE
@@ -0,0 +1,12 @@
+Copyright Arch Linux Contributors
+
+Permission to use, copy, modify, and/or distribute this software for
+any purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/linhes/qt5-webengine/LICENSES/0BSD.txt b/linhes/qt5-webengine/LICENSES/0BSD.txt
new file mode 120000
index 0000000..ea5b606
--- /dev/null
+++ b/linhes/qt5-webengine/LICENSES/0BSD.txt
@@ -0,0 +1 @@
+../LICENSE
\ No newline at end of file
diff --git a/linhes/qt5-webengine/LICENSES/BSD-3-Clause.txt b/linhes/qt5-webengine/LICENSES/BSD-3-Clause.txt
new file mode 100644
index 0000000..ea890af
--- /dev/null
+++ b/linhes/qt5-webengine/LICENSES/BSD-3-Clause.txt
@@ -0,0 +1,11 @@
+Copyright (c) <year> <owner>. 
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/linhes/qt5-webengine/PKGBUILD b/linhes/qt5-webengine/PKGBUILD
new file mode 100644
index 0000000..eca0c9a
--- /dev/null
+++ b/linhes/qt5-webengine/PKGBUILD
@@ -0,0 +1,87 @@
+# Maintainer: Felix Yan <felixonmars@archlinux.org>
+# Contributor: Andrea Scarpino <andrea@archlinux.org>
+
+pkgname=qt5-webengine
+_basever=5.15.18
+pkgver=5.15.19
+pkgrel=4
+arch=('x86_64')
+url='https://www.qt.io'
+license=('LGPL3' 'LGPL2.1' 'BSD')
+pkgdesc='Provides support for web applications using the Chromium browser project'
+depends=('qt5-webchannel' 'qt5-location' 'libxcomposite' 'libxrandr' 'pciutils' 'libxss' 'libxkbfile' 'libxdamage'
+         'libevent' 'snappy' 'nss' 'libxslt' 'minizip' 'ffmpeg' 'libvpx' 'libxtst' 'ttf-font')
+makedepends=('git' 'python' 'gperf' 'jsoncpp' 'ninja' 'qt5-tools' 'poppler' 'pipewire' 'nodejs' 'python-html5lib')
+optdepends=('pipewire: WebRTC desktop sharing under Wayland')
+groups=('qt5')
+_pkgfqn=${pkgname/5-/}
+source=(kde-$_pkgfqn::git+https://code.qt.io/qt/qtwebengine.git#tag=v${pkgver}-lts
+        git+https://code.qt.io/qt/qtwebengine-chromium.git
+        qt5-webengine-pipewire-0.3.patch
+        qt5-webengine-icu-75.patch
+        qt5-webengine-ninja-1.12.patch
+        qt5-webengine-gcc-15.patch
+        python3.12-six.patch
+        qt5-webengine-icu-78.patch)
+sha256sums=('10ae73fd623eff84af2921ea2c83c723d9a847e23abbc8d862d0dc346382ef9b'
+            'SKIP'
+            '5e3a3c4711d964d5152a04059a2b5c1d14bb13dd29bce370120f60e85b476b6f'
+            '7cac28ba784d24b4abf6414079548ada165343af507ecd8e23cbe7e4f63ae52f'
+            '6672741b64d896dc555c8ee42ca2329c4f20d5f406095a69fe72da44b3a142f4'
+            '813851a1c7de9947afab28b7f3cb26ca739254521f12c21f76a6a3ec164def24'
+            'ac87ec55ee5cbcf2d520e1ea433d041c0bf754271a17f859edbb9976f192ce3f'
+            'f5cf66e4006ca81def2625088e7dd2fc925a0a617b4b88d1a19f030b60b9ad96')
+
+prepare() {
+  mkdir -p build
+
+  cd kde-$_pkgfqn
+  git submodule init
+  git submodule set-url src/3rdparty "$srcdir"/qtwebengine-chromium
+  git submodule set-branch --branch 87-based src/3rdparty
+  git -c protocol.file.allow=always submodule update
+
+  patch -p1 -d src/3rdparty -i "$srcdir"/qt5-webengine-pipewire-0.3.patch # Port to pipewire 0.3
+  patch -p2 -d src/3rdparty/chromium -i "$srcdir"/qt5-webengine-icu-75.patch # Fix build with ICU 75
+  patch -p2 -d src/3rdparty/chromium -i "$srcdir"/qt5-webengine-ninja-1.12.patch # Fix build with ninja 1.12
+  patch -p1 -d src/3rdparty/chromium -i "$srcdir"/python3.12-six.patch # Fix build with python 3.12 - patch from Debian
+  patch -p1 -i "$srcdir"/qt5-webengine-gcc-15.patch # Fix build with GCC 15 (Fedora)
+  patch -Np1 -i "$srcdir"/qt5-webengine-icu-78.patch # Fix build with ICU78
+# Fix build with python 3.13
+  sed -e '/import pipes/d' -i src/3rdparty/chromium/build/android/gyp/util/build_utils.py
+}
+
+build() {
+  # this uses malloc_usable_size, which is incompatible with fortification level 3
+  export CFLAGS="${CFLAGS/_FORTIFY_SOURCE=3/_FORTIFY_SOURCE=2}"
+  export CXXFLAGS="${CXXFLAGS/_FORTIFY_SOURCE=3/_FORTIFY_SOURCE=2}"
+
+  cd build
+  qmake ../kde-$_pkgfqn CONFIG+=force_debug_info -- \
+    -proprietary-codecs \
+    -webp \
+    -webengine-icu \
+    -spellchecker \
+    -webengine-kerberos \
+    -webengine-webrtc-pipewire \
+    -webengine-python-version python3
+  make
+}
+
+package() {
+  # this uses malloc_usable_size, which is incompatible with fortification level 3
+  export CFLAGS="${CFLAGS/_FORTIFY_SOURCE=3/_FORTIFY_SOURCE=2}"
+  export CXXFLAGS="${CXXFLAGS/_FORTIFY_SOURCE=3/_FORTIFY_SOURCE=2}"
+
+  cd build
+  make INSTALL_ROOT="$pkgdir" install
+
+  # Drop QMAKE_PRL_BUILD_DIR because reference the build dir
+  find "$pkgdir/usr/lib" -type f -name '*.prl' \
+    -exec sed -i -e '/^QMAKE_PRL_BUILD_DIR/d' {} \;
+
+  install -Dm644 "$srcdir"/kde-$_pkgfqn/src/3rdparty/chromium/LICENSE "$pkgdir"/usr/share/licenses/${pkgname}/LICENSE.chromium
+
+  # Fix cmake dependency versions
+  sed -e "s|$pkgver\ |$_basever |" -i "$pkgdir"/usr/lib/cmake/*/*Config.cmake
+}
diff --git a/linhes/qt5-webengine/README.md b/linhes/qt5-webengine/README.md
new file mode 100644
index 0000000..9c4dc74
--- /dev/null
+++ b/linhes/qt5-webengine/README.md
@@ -0,0 +1,3 @@
+This package is part of the `qt5` suite, and is managed by the scripts at https://gitlab.archlinux.org/archlinux/kde-build.
+
+Do not upgrade this package individually, or make any format changes to the PKGBUILD without checking with the Qt package maintainers first.
diff --git a/linhes/qt5-webengine/REUSE.toml b/linhes/qt5-webengine/REUSE.toml
new file mode 100644
index 0000000..956ef39
--- /dev/null
+++ b/linhes/qt5-webengine/REUSE.toml
@@ -0,0 +1,36 @@
+version = 1
+
+[[annotations]]
+path = [
+    "PKGBUILD",
+    "README.md",
+    "keys/**",
+    ".SRCINFO",
+    ".nvchecker.toml",
+    "*.install",
+    "*.sysusers",
+    "*.tmpfiles",
+    "*.logrotate",
+    "*.pam",
+    "*.service",
+    "*.socket",
+    "*.timer",
+    "*.desktop",
+    "*.hook",
+]
+SPDX-FileCopyrightText = "Arch Linux contributors"
+SPDX-License-Identifier = "0BSD"
+
+[[annotations]]
+path = [
+    "python3.12-imp.patch",
+    "python3.12-six.patch",
+    "qt5-webengine-ffmpeg5.patch",
+    "qt5-webengine-ffmpeg7.patch",
+    "qt5-webengine-gcc-15.patch",
+    "qt5-webengine-icu-75.patch",
+    "qt5-webengine-ninja-1.12.patch",
+    "qt5-webengine-pipewire-0.3.patch",
+]
+SPDX-FileCopyrightText = "qt5-webengine contributors"
+SPDX-License-Identifier = "BSD-3-Clause"
diff --git a/linhes/qt5-webengine/python3.12-imp.patch b/linhes/qt5-webengine/python3.12-imp.patch
new file mode 100644
index 0000000..f7cb480
--- /dev/null
+++ b/linhes/qt5-webengine/python3.12-imp.patch
@@ -0,0 +1,26 @@
+Description: stop using imp module which was removed in Python 3.12
+Origin: upstream, commits
+ https://chromium.googlesource.com/chromium/src/+/9e0c89a3b5638ba2
+ https://chromium.googlesource.com/chromium/src/+/f5f6e361d037c316
+Last-Update: 2024-03-17
+
+--- a/mojo/public/tools/mojom/mojom/fileutil.py
++++ b/mojo/public/tools/mojom/mojom/fileutil.py
+@@ -3,7 +3,6 @@
+ # found in the LICENSE file.
+ 
+ import errno
+-import imp
+ import os.path
+ import sys
+ 
+--- a/mojo/public/tools/mojom/mojom/parse/lexer.py
++++ b/mojo/public/tools/mojom/mojom/parse/lexer.py
+@@ -2,7 +2,6 @@
+ # Use of this source code is governed by a BSD-style license that can be
+ # found in the LICENSE file.
+ 
+-import imp
+ import os.path
+ import sys
+ 
diff --git a/linhes/qt5-webengine/python3.12-six.patch b/linhes/qt5-webengine/python3.12-six.patch
new file mode 100644
index 0000000..4aef50b
--- /dev/null
+++ b/linhes/qt5-webengine/python3.12-six.patch
@@ -0,0 +1,58 @@
+Patch-Source: https://sources.debian.org/data/main/q/qtwebengine-opensource-src/5.15.16+dfsg-3/debian/patches/python3.12-six.patch
+--
+Description: implement find_spec() for _SixMetaPathImporter
+Origin: upstream, https://github.com/benjaminp/six/commit/25916292d96f5f09
+Last-Update: 2024-03-17
+
+--- a/third_party/protobuf/third_party/six/six.py
++++ b/third_party/protobuf/third_party/six/six.py
+@@ -71,6 +71,11 @@ else:
+             MAXSIZE = int((1 << 63) - 1)
+         del X
+ 
++if PY34:
++    from importlib.util import spec_from_loader
++else:
++    spec_from_loader = None
++
+ 
+ def _add_doc(func, doc):
+     """Add documentation to a function."""
+@@ -186,6 +191,11 @@ class _SixMetaPathImporter(object):
+             return self
+         return None
+ 
++    def find_spec(self, fullname, path, target=None):
++        if fullname in self.known_modules:
++            return spec_from_loader(fullname, self)
++        return None
++
+     def __get_module(self, fullname):
+         try:
+             return self.known_modules[fullname]
+--- a/tools/grit/third_party/six/__init__.py
++++ b/tools/grit/third_party/six/__init__.py
+@@ -71,6 +71,11 @@ else:
+             MAXSIZE = int((1 << 63) - 1)
+         del X
+ 
++if PY34:
++    from importlib.util import spec_from_loader
++else:
++    spec_from_loader = None
++
+ 
+ def _add_doc(func, doc):
+     """Add documentation to a function."""
+@@ -186,6 +191,11 @@ class _SixMetaPathImporter(object):
+             return self
+         return None
+ 
++    def find_spec(self, fullname, path, target=None):
++        if fullname in self.known_modules:
++            return spec_from_loader(fullname, self)
++        return None
++
+     def __get_module(self, fullname):
+         try:
+             return self.known_modules[fullname]
diff --git a/linhes/qt5-webengine/qt5-webengine-gcc-15.patch b/linhes/qt5-webengine/qt5-webengine-gcc-15.patch
new file mode 100644
index 0000000..4b47240
--- /dev/null
+++ b/linhes/qt5-webengine/qt5-webengine-gcc-15.patch
@@ -0,0 +1,443 @@
+diff --git a/src/3rdparty/chromium/base/debug/profiler.h b/src/3rdparty/chromium/base/debug/profiler.h
+index be6e272e0..b27f5f690 100644
+--- a/src/3rdparty/chromium/base/debug/profiler.h
++++ b/src/3rdparty/chromium/base/debug/profiler.h
+@@ -5,6 +5,7 @@
+ #ifndef BASE_DEBUG_PROFILER_H_
+ #define BASE_DEBUG_PROFILER_H_
+
++#include <cstdint>
+ #include <stddef.h>
+ #include <cstdint>
+
+diff --git a/src/3rdparty/chromium/cc/trees/target_property.cc b/src/3rdparty/chromium/cc/trees/target_property.cc
+index 00595fda0..ebd8c605a 100644
+--- a/src/3rdparty/chromium/cc/trees/target_property.cc
++++ b/src/3rdparty/chromium/cc/trees/target_property.cc
+@@ -6,6 +6,10 @@
+
+ #include "cc/trees/target_property.h"
+
++#include <cstdint>
++
++#include <cstdint>
++
+ namespace cc {
+
+ static_assert(TargetProperty::LAST_TARGET_PROPERTY < kMaxTargetPropertyIndex,
+diff --git a/src/3rdparty/chromium/device/base/synchronization/one_writer_seqlock.cc b/src/3rdparty/chromium/device/base/synchronization/one_writer_seqlock.cc
+index 98266a16c..7676e6097 100644
+--- a/src/3rdparty/chromium/device/base/synchronization/one_writer_seqlock.cc
++++ b/src/3rdparty/chromium/device/base/synchronization/one_writer_seqlock.cc
+@@ -6,6 +6,8 @@
+
+ #include "device/base/synchronization/one_writer_seqlock.h"
+
++#include <cstdint>
++
+ namespace device {
+
+ OneWriterSeqLock::OneWriterSeqLock() : sequence_(0) {}
+diff --git a/src/3rdparty/chromium/extensions/common/constants.h b/src/3rdparty/chromium/extensions/common/constants.h
+index e6183dc11..5a12758ac 100644
+--- a/src/3rdparty/chromium/extensions/common/constants.h
++++ b/src/3rdparty/chromium/extensions/common/constants.h
+@@ -13,6 +13,8 @@
+ #include "components/version_info/channel.h"
+ #include "ui/base/layout.h"
+
++#include <cstdint>
++
+ namespace extensions {
+
+ // Scheme we serve extension content from.
+diff --git a/src/3rdparty/chromium/gpu/config/gpu_preferences.h b/src/3rdparty/chromium/gpu/config/gpu_preferences.h
+index 57bda1f99..7a5ef9b3a 100644
+--- a/src/3rdparty/chromium/gpu/config/gpu_preferences.h
++++ b/src/3rdparty/chromium/gpu/config/gpu_preferences.h
+@@ -5,6 +5,7 @@
+ #ifndef GPU_CONFIG_GPU_PREFERENCES_H_
+ #define GPU_CONFIG_GPU_PREFERENCES_H_
+
++#include <cstdint>
+ #include <stddef.h>
+ #include <cstdint>
+ #include <string>
+diff --git a/src/3rdparty/chromium/net/base/parse_number.h b/src/3rdparty/chromium/net/base/parse_number.h
+index 301d14ac8..378058a23 100644
+--- a/src/3rdparty/chromium/net/base/parse_number.h
++++ b/src/3rdparty/chromium/net/base/parse_number.h
+@@ -11,6 +11,8 @@
+ #include "base/strings/string_piece.h"
+ #include "net/base/net_export.h"
+
++#include <cstdint>
++
+ // This file contains utility functions for parsing numbers, in the context of
+ // network protocols.
+ //
+diff --git a/src/3rdparty/chromium/pdf/document_attachment_info.h b/src/3rdparty/chromium/pdf/document_attachment_info.h
+index fd78cb729..f9330a0db 100644
+--- a/src/3rdparty/chromium/pdf/document_attachment_info.h
++++ b/src/3rdparty/chromium/pdf/document_attachment_info.h
+@@ -9,6 +9,8 @@
+
+ #include "base/strings/string16.h"
+
++#include <cstdint>
++
+ namespace chrome_pdf {
+
+ struct DocumentAttachmentInfo {
+diff --git a/src/3rdparty/chromium/ppapi/utility/completion_callback_factory_thread_traits.h b/src/3rdparty/chromium/ppapi/utility/completion_callback_factory_thread_traits.h
+index ac0b31a75..5d1c421d0 100644
+--- a/src/3rdparty/chromium/ppapi/utility/completion_callback_factory_thread_traits.h
++++ b/src/3rdparty/chromium/ppapi/utility/completion_callback_factory_thread_traits.h
+@@ -38,6 +38,10 @@ namespace pp {
+ /// As a further optimization, we can add support for this later.
+ class ThreadSafeThreadTraits {
+  public:
++
++  typedef pp::Lock Lock;
++  typedef pp::AutoLock AutoLock;
++
+   class RefCount {
+    public:
+     /// Default constructor. In debug mode, this checks that the object is being
+@@ -67,8 +71,6 @@ class ThreadSafeThreadTraits {
+     int32_t ref_;
+   };
+
+-  typedef pp::Lock Lock;
+-  typedef pp::AutoLock AutoLock;
+ };
+
+ /// The non-thread-safe version of thread traits. Using this class as the
+diff --git a/src/3rdparty/chromium/third_party/angle/src/common/angleutils.h b/src/3rdparty/chromium/third_party/angle/src/common/angleutils.h
+index fb9a44225..f9330f313 100644
+--- a/src/3rdparty/chromium/third_party/angle/src/common/angleutils.h
++++ b/src/3rdparty/chromium/third_party/angle/src/common/angleutils.h
+@@ -15,6 +15,7 @@
+ #    include "absl/container/flat_hash_map.h"
+ #endif  // defined(ANGLE_USE_ABSEIL)
+
++#include <cstdint>
+ #include <climits>
+ #include <cstdarg>
+ #include <cstddef>
+diff --git a/src/3rdparty/chromium/third_party/libgav1/src/src/utils/threadpool.cc b/src/3rdparty/chromium/third_party/libgav1/src/src/utils/threadpool.cc
+index 4e8788bc4..a5d35b31b 100644
+--- a/src/3rdparty/chromium/third_party/libgav1/src/src/utils/threadpool.cc
++++ b/src/3rdparty/chromium/third_party/libgav1/src/src/utils/threadpool.cc
+@@ -31,6 +31,7 @@
+ #include <cstdio>
+ #include <cstdint>
+ #include <cstring>
++#include <cstdio>
+ #include <new>
+ #include <utility>
+
+diff --git a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/proto/proto_importer_module.h b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/proto/proto_importer_module.h
+index 098433c47..0820bb220 100644
+--- a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/proto/proto_importer_module.h
++++ b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/proto/proto_importer_module.h
+@@ -23,6 +23,8 @@
+ #include "perfetto/trace_processor/status.h"
+ #include "src/trace_processor/trace_blob_view.h"
+
++#include <cstdint>
++
+ namespace perfetto {
+
+ namespace protos {
+diff --git a/src/3rdparty/chromium/ui/events/gesture_event_details.h b/src/3rdparty/chromium/ui/events/gesture_event_details.h
+index d20416738..8dadab3d0 100644
+--- a/src/3rdparty/chromium/ui/events/gesture_event_details.h
++++ b/src/3rdparty/chromium/ui/events/gesture_event_details.h
+@@ -5,6 +5,7 @@
+ #ifndef UI_EVENTS_GESTURE_DETECTION_GESTURE_EVENT_DETAILS_H_
+ #define UI_EVENTS_GESTURE_DETECTION_GESTURE_EVENT_DETAILS_H_
+
++#include <cstdint>
+ #include <string.h>
+
+ #include "base/check_op.h"
+diff --git a/src/3rdparty/chromium/ui/gl/gl_surface_glx.cc b/src/3rdparty/chromium/ui/gl/gl_surface_glx.cc
+index 1d5527691..ef9d5ce13 100644
+--- a/src/3rdparty/chromium/ui/gl/gl_surface_glx.cc
++++ b/src/3rdparty/chromium/ui/gl/gl_surface_glx.cc
+@@ -4,6 +4,7 @@
+
+ #include "ui/gl/gl_surface_glx.h"
+
++#include <cstdint>
+ #include <utility>
+
+ #include "base/bind.h"
+diff --git a/src/3rdparty/chromium/ui/gl/gl_surface_glx.h b/src/3rdparty/chromium/ui/gl/gl_surface_glx.h
+index ab612cd87..2178d8514 100644
+--- a/src/3rdparty/chromium/ui/gl/gl_surface_glx.h
++++ b/src/3rdparty/chromium/ui/gl/gl_surface_glx.h
+@@ -5,6 +5,7 @@
+ #ifndef UI_GL_GL_SURFACE_GLX_H_
+ #define UI_GL_GL_SURFACE_GLX_H_
+
++#include <cstdint>
+ #include <stdint.h>
+
+ #include <memory>
+diff --git a/src/3rdparty/chromium/v8/src/base/logging.h b/src/3rdparty/chromium/v8/src/base/logging.h
+index 7c774ed30..1c44cf72a 100644
+--- a/src/3rdparty/chromium/v8/src/base/logging.h
++++ b/src/3rdparty/chromium/v8/src/base/logging.h
+@@ -5,6 +5,7 @@
+ #ifndef V8_BASE_LOGGING_H_
+ #define V8_BASE_LOGGING_H_
+
++#include <cstdint>
+ #include <cstring>
+ #include <cstdint>
+ #include <sstream>
+diff --git a/src/core/browsing_data_remover_delegate_qt.h b/src/core/browsing_data_remover_delegate_qt.h
+index 5adfbbe7e..4e5c59e33 100644
+--- a/src/core/browsing_data_remover_delegate_qt.h
++++ b/src/core/browsing_data_remover_delegate_qt.h
+@@ -44,6 +44,8 @@
+
+ #include "content/public/browser/browsing_data_remover_delegate.h"
+
++#include <cstdint>
++
+ namespace QtWebEngineCore {
+
+ class BrowsingDataRemoverDelegateQt : public content::BrowsingDataRemoverDelegate {
+diff --git a/src/3rdparty/chromium/third_party/webrtc/api/task_queue/task_queue_base.h b/src/3rdparty/chromium/third_party/webrtc/api/task_queue/task_queue_base.h
+index 90b1efd31..63526a738 100644
+--- a/src/3rdparty/chromium/third_party/webrtc/api/task_queue/task_queue_base.h
++++ b/src/3rdparty/chromium/third_party/webrtc/api/task_queue/task_queue_base.h
+@@ -10,6 +10,7 @@
+ #ifndef API_TASK_QUEUE_TASK_QUEUE_BASE_H_
+ #define API_TASK_QUEUE_TASK_QUEUE_BASE_H_
+ 
++#include <cstdint>
+ #include <memory>
+ 
+ #include "api/task_queue/queued_task.h"
+diff --git a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.cc b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.cc
+index 8a30c7f32..4934432cc 100644
+--- a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.cc
++++ b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.cc
+@@ -20,6 +20,8 @@
+ #include "perfetto/base/build_config.h"
+ #include "perfetto/base/compiler.h"
+ 
++#include <cstdint>
++
+ #if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+ #include <zlib.h>
+ #else
+diff --git a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.h b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.h
+index 624363ff6..6d717fba4 100644
+--- a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.h
++++ b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.h
+@@ -17,6 +17,7 @@
+ #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_GZIP_GZIP_UTILS_H_
+ #define SRC_TRACE_PROCESSOR_IMPORTERS_GZIP_GZIP_UTILS_H_
+ 
++#include <cstdint>
+ #include <memory>
+ 
+ struct z_stream_s;
+diff --git a/src/3rdparty/chromium/third_party/perfetto/include/perfetto/ext/tracing/core/slice.h b/src/3rdparty/chromium/third_party/perfetto/include/perfetto/ext/tracing/core/slice.h
+index 4ce66fdea..3f3932b22 100644
+--- a/src/3rdparty/chromium/third_party/perfetto/include/perfetto/ext/tracing/core/slice.h
++++ b/src/3rdparty/chromium/third_party/perfetto/include/perfetto/ext/tracing/core/slice.h
+@@ -20,6 +20,7 @@
+ #include <stddef.h>
+ #include <string.h>
+ 
++#include <cstdint>
+ #include <memory>
+ #include <string>
+ #include <vector>
+diff --git a/src/3rdparty/chromium/third_party/perfetto/src/tracing/core/trace_packet.cc b/src/3rdparty/chromium/third_party/perfetto/src/tracing/core/trace_packet.cc
+index 0dea150c1..c3def1683 100644
+--- a/src/3rdparty/chromium/third_party/perfetto/src/tracing/core/trace_packet.cc
++++ b/src/3rdparty/chromium/third_party/perfetto/src/tracing/core/trace_packet.cc
+@@ -19,6 +19,8 @@
+ #include "perfetto/base/logging.h"
+ #include "perfetto/protozero/proto_utils.h"
+ 
++#include <cstdint>
++
+ namespace perfetto {
+ 
+ TracePacket::TracePacket() = default;
+diff --git a/src/3rdparty/chromium/third_party/perfetto/include/perfetto/tracing/tracing_backend.h b/src/3rdparty/chromium/third_party/perfetto/include/perfetto/tracing/tracing_backend.h
+index 67b0d2eb5..3c2462de5 100644
+--- a/src/3rdparty/chromium/third_party/perfetto/include/perfetto/tracing/tracing_backend.h
++++ b/src/3rdparty/chromium/third_party/perfetto/include/perfetto/tracing/tracing_backend.h
+@@ -17,6 +17,7 @@
+ #ifndef INCLUDE_PERFETTO_TRACING_TRACING_BACKEND_H_
+ #define INCLUDE_PERFETTO_TRACING_TRACING_BACKEND_H_
+ 
++#include <cstdint>
+ #include <memory>
+ #include <string>
+ 
+diff --git a/src/3rdparty/chromium/base/task/thread_pool.h b/src/3rdparty/chromium/base/task/thread_pool.h
+index 085c249ba..afc674ca7 100644
+--- a/src/3rdparty/chromium/base/task/thread_pool.h
++++ b/src/3rdparty/chromium/base/task/thread_pool.h
+@@ -5,6 +5,7 @@
+ #ifndef BASE_TASK_THREAD_POOL_H_
+ #define BASE_TASK_THREAD_POOL_H_
+ 
++#include <cstdint>
+ #include <memory>
+ #include <utility>
+ 
+diff --git a/src/3rdparty/chromium/net/tools/huffman_trie/trie_entry.h b/src/3rdparty/chromium/net/tools/huffman_trie/trie_entry.h
+index fe70260f9..eac6a7fc2 100644
+--- a/src/3rdparty/chromium/net/tools/huffman_trie/trie_entry.h
++++ b/src/3rdparty/chromium/net/tools/huffman_trie/trie_entry.h
+@@ -5,6 +5,7 @@
+ #ifndef NET_TOOLS_HUFFMAN_TRIE_TRIE_ENTRY_H_
+ #define NET_TOOLS_HUFFMAN_TRIE_TRIE_ENTRY_H_
+ 
++#include <cstdint>
+ #include <memory>
+ #include <string>
+ #include <vector>
+diff --git a/src/3rdparty/chromium/third_party/webrtc/api/fec_controller.h b/src/3rdparty/chromium/third_party/webrtc/api/fec_controller.h
+index 3e5f7bb21..87777a53f 100644
+--- a/src/3rdparty/chromium/third_party/webrtc/api/fec_controller.h
++++ b/src/3rdparty/chromium/third_party/webrtc/api/fec_controller.h
+@@ -11,6 +11,7 @@
+ #ifndef API_FEC_CONTROLLER_H_
+ #define API_FEC_CONTROLLER_H_
+ 
++#include <cstdint>
+ #include <memory>
+ #include <vector>
+ 
+diff --git a/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/timestamp_map.h b/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/timestamp_map.h
+index c85666c9a..dfb90e447 100644
+--- a/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/timestamp_map.h
++++ b/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/timestamp_map.h
+@@ -11,6 +11,7 @@
+ #ifndef MODULES_VIDEO_CODING_TIMESTAMP_MAP_H_
+ #define MODULES_VIDEO_CODING_TIMESTAMP_MAP_H_
+ 
++#include <cstdint>
+ #include <memory>
+ 
+ namespace webrtc {
+diff --git a/src/3rdparty/chromium/third_party/webrtc/api/network_state_predictor.h b/src/3rdparty/chromium/third_party/webrtc/api/network_state_predictor.h
+index 9cf5ab6f0..2d165baa5 100644
+--- a/src/3rdparty/chromium/third_party/webrtc/api/network_state_predictor.h
++++ b/src/3rdparty/chromium/third_party/webrtc/api/network_state_predictor.h
+@@ -11,6 +11,7 @@
+ #ifndef API_NETWORK_STATE_PREDICTOR_H_
+ #define API_NETWORK_STATE_PREDICTOR_H_
+ 
++#include <cstdint>
+ #include <memory>
+ #include <vector>
+ 
+diff --git a/src/3rdparty/chromium/gpu/command_buffer/common/skia_utils.h b/src/3rdparty/chromium/gpu/command_buffer/common/skia_utils.h
+index 6508d79a1..a9f9528f1 100644
+--- a/src/3rdparty/chromium/gpu/command_buffer/common/skia_utils.h
++++ b/src/3rdparty/chromium/gpu/command_buffer/common/skia_utils.h
+@@ -5,6 +5,7 @@
+ #ifndef GPU_COMMAND_BUFFER_COMMON_SKIA_UTILS_H_
+ #define GPU_COMMAND_BUFFER_COMMON_SKIA_UTILS_H_
+ 
++#include <cstdint>
+ #include <memory>
+ 
+ #include "base/optional.h"
+diff --git a/src/3rdparty/chromium/gpu/command_buffer/service/gpu_fence_manager.h b/src/3rdparty/chromium/gpu/command_buffer/service/gpu_fence_manager.h
+index ee50d6fdd..576f6e3bc 100644
+--- a/src/3rdparty/chromium/gpu/command_buffer/service/gpu_fence_manager.h
++++ b/src/3rdparty/chromium/gpu/command_buffer/service/gpu_fence_manager.h
+@@ -5,6 +5,7 @@
+ #ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_FENCE_MANAGER_H_
+ #define GPU_COMMAND_BUFFER_SERVICE_GPU_FENCE_MANAGER_H_
+ 
++#include <cstdint>
+ #include <memory>
+ #include <vector>
+ 
+diff --git a/src/3rdparty/chromium/third_party/pdfium/core/fpdfapi/page/cpdf_function.h b/src/3rdparty/chromium/third_party/pdfium/core/fpdfapi/page/cpdf_function.h
+index fd68b6b49..dc7c015d5 100644
+--- a/src/3rdparty/chromium/third_party/pdfium/core/fpdfapi/page/cpdf_function.h
++++ b/src/3rdparty/chromium/third_party/pdfium/core/fpdfapi/page/cpdf_function.h
+@@ -7,6 +7,7 @@
+ #ifndef CORE_FPDFAPI_PAGE_CPDF_FUNCTION_H_
+ #define CORE_FPDFAPI_PAGE_CPDF_FUNCTION_H_
+ 
++#include <cstdint>
+ #include <memory>
+ #include <set>
+ #include <vector>
+diff --git a/src/3rdparty/chromium/third_party/pdfium/core/fxcodec/jbig2/JBig2_DocumentContext.h b/src/3rdparty/chromium/third_party/pdfium/core/fxcodec/jbig2/JBig2_DocumentContext.h
+index 9bcdd371e..5921794f1 100644
+--- a/src/3rdparty/chromium/third_party/pdfium/core/fxcodec/jbig2/JBig2_DocumentContext.h
++++ b/src/3rdparty/chromium/third_party/pdfium/core/fxcodec/jbig2/JBig2_DocumentContext.h
+@@ -7,6 +7,7 @@
+ #ifndef CORE_FXCODEC_JBIG2_JBIG2_DOCUMENTCONTEXT_H_
+ #define CORE_FXCODEC_JBIG2_JBIG2_DOCUMENTCONTEXT_H_
+ 
++#include <cstdint>
+ #include <list>
+ #include <memory>
+ #include <utility>
+diff --git a/src/3rdparty/chromium/third_party/pdfium/third_party/base/span.h b/src/3rdparty/chromium/third_party/pdfium/third_party/base/span.h
+index bb07f43a0..0b7daf775 100644
+--- a/src/3rdparty/chromium/third_party/pdfium/third_party/base/span.h
++++ b/src/3rdparty/chromium/third_party/pdfium/third_party/base/span.h
+@@ -9,6 +9,7 @@
+ 
+ #include <algorithm>
+ #include <array>
++#include <cstdint>
+ #include <iterator>
+ #include <type_traits>
+ #include <utility>
+diff --git a/src/3rdparty/chromium/third_party/webrtc/video/stats_counter.h b/src/3rdparty/chromium/third_party/webrtc/video/stats_counter.h
+index fb6017f41..ed5530ca0 100644
+--- a/src/3rdparty/chromium/third_party/webrtc/video/stats_counter.h
++++ b/src/3rdparty/chromium/third_party/webrtc/video/stats_counter.h
+@@ -11,6 +11,7 @@
+ #ifndef VIDEO_STATS_COUNTER_H_
+ #define VIDEO_STATS_COUNTER_H_
+ 
++#include <cstdint>
+ #include <memory>
+ #include <string>
+ 
+diff --git a/src/3rdparty/chromium/third_party/woff2/include/woff2/output.h b/src/3rdparty/chromium/third_party/woff2/include/woff2/output.h
+index c325f67be..5c4dc4d18 100644
+--- a/src/3rdparty/chromium/third_party/woff2/include/woff2/output.h
++++ b/src/3rdparty/chromium/third_party/woff2/include/woff2/output.h
+@@ -10,6 +10,7 @@
+ #define WOFF2_WOFF2_OUT_H_
+ 
+ #include <algorithm>
++#include <cstdint>
+ #include <cstring>
+ #include <memory>
+ #include <string>
+diff --git a/chromium/cc/input/main_thread_scrolling_reason.h b/chromium/cc/input/main_thread_scrolling_reason.h
+index 4ddd536afcc..dc1bc072790 100644
+--- a/src/3rdparty/chromium/cc/input/main_thread_scrolling_reason.h
++++ b/src/3rdparty/chromium/cc/input/main_thread_scrolling_reason.h
+@@ -7,6 +7,7 @@
+ 
+ #include <memory>
+ #include <string>
++#include <cstdint>
+ #include "cc/cc_export.h"
+ 
+ namespace base {
diff --git a/linhes/qt5-webengine/qt5-webengine-icu-75.patch b/linhes/qt5-webengine/qt5-webengine-icu-75.patch
new file mode 100644
index 0000000..6178a2c
--- /dev/null
+++ b/linhes/qt5-webengine/qt5-webengine-icu-75.patch
@@ -0,0 +1,99 @@
+diff --git a/chromium/build/config/compiler/BUILD.gn b/chromium/build/config/compiler/BUILD.gn
+index b511a58c5a8..abd78a74ead 100644
+--- a/chromium/build/config/compiler/BUILD.gn
++++ b/chromium/build/config/compiler/BUILD.gn
+@@ -566,7 +566,7 @@ config("compiler") {
+       # Override Chromium's default for projects that wish to stay on C++11.
+       cflags_cc += [ "-std=${standard_prefix}++11" ]
+     } else {
+-      cflags_cc += [ "-std=${standard_prefix}++14" ]
++      cflags_cc += [ "-std=${standard_prefix}++17" ]
+     }
+   } else if (!is_win && !is_nacl) {
+     if (target_os == "android") {
+diff --git a/chromium/base/allocator/partition_allocator/partition_alloc_constants.h b/chromium/base/allocator/partition_allocator/partition_alloc_constants.h
+index f03ba1e4ab4..b1495f7ae74 100644
+--- a/chromium/base/allocator/partition_allocator/partition_alloc_constants.h
++++ b/chromium/base/allocator/partition_allocator/partition_alloc_constants.h
+@@ -195,7 +195,7 @@ NumPartitionPagesPerSuperPage() {
+ //
+ // __STDCPP_DEFAULT_NEW_ALIGNMENT__ is C++17. As such, it is not defined on all
+ // platforms, as Chrome's requirement is C++14 as of 2020.
+-#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
++#if 0
+ static constexpr size_t kAlignment =
+     std::max(alignof(std::max_align_t), __STDCPP_DEFAULT_NEW_ALIGNMENT__);
+ #else
+diff --git a/chromium/third_party/webrtc/common_video/h264/sps_parser.h b/chromium/third_party/webrtc/common_video/h264/sps_parser.h
+index 76e627d27a3..942435f44a0 100644
+--- a/chromium/third_party/webrtc/common_video/h264/sps_parser.h
++++ b/chromium/third_party/webrtc/common_video/h264/sps_parser.h
+@@ -12,6 +12,7 @@
+ #define COMMON_VIDEO_H264_SPS_PARSER_H_
+ 
+ #include "absl/types/optional.h"
++#include <cstdint>
+ 
+ namespace rtc {
+ class BitBuffer;
+diff --git a/chromium/third_party/webrtc/common_video/h264/pps_parser.h b/chromium/third_party/webrtc/common_video/h264/pps_parser.h
+index d6c31b06887..d8852dfd186 100644
+--- a/chromium/third_party/webrtc/common_video/h264/pps_parser.h
++++ b/chromium/third_party/webrtc/common_video/h264/pps_parser.h
+@@ -12,6 +12,7 @@
+ #define COMMON_VIDEO_H264_PPS_PARSER_H_
+ 
+ #include "absl/types/optional.h"
++#include <cstdint>
+ 
+ namespace rtc {
+ class BitBuffer;
+diff --git a/chromium/third_party/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h b/chromium/third_party/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h
+index 3b9971abae1..d4458038527 100644
+--- a/chromium/third_party/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h
++++ b/chromium/third_party/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h
+@@ -13,6 +13,7 @@
+ 
+ #include <array>
+ #include <vector>
++#include <memory>
+ 
+ #include "absl/types/optional.h"
+ #include "api/array_view.h"
+diff --git a/chromium/third_party/webrtc/modules/include/module_common_types_public.h b/chromium/third_party/webrtc/modules/include/module_common_types_public.h
+index 345e45ce127..e686e5d691a 100644
+--- a/chromium/third_party/webrtc/modules/include/module_common_types_public.h
++++ b/chromium/third_party/webrtc/modules/include/module_common_types_public.h
+@@ -12,6 +12,7 @@
+ #define MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
+ 
+ #include <limits>
++#include <cstdint>
+ 
+ #include "absl/types/optional.h"
+ 
+diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
+index 8fcc799b795..bc69ddcf18c 100644
+--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
++++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
+@@ -15,6 +15,7 @@
+ #include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h"
+ #include "third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h"
+ #include "third_party/blink/renderer/platform/text/text_boundaries.h"
++#include "absl/base/attributes.h"
+ 
+ namespace blink {
+ 
+diff --git a/chromium/third_party/abseil-cpp/absl/base/options.h b/chromium/third_party/abseil-cpp/absl/base/options.h
+index df506f0fae6..1de105fed4a 100644
+--- a/chromium/third_party/abseil-cpp/absl/base/options.h
++++ b/chromium/third_party/abseil-cpp/absl/base/options.h
+@@ -180,7 +180,7 @@
+ // absl::variant is a typedef of std::variant, use the feature macro
+ // ABSL_USES_STD_VARIANT.
+ 
+-#define ABSL_OPTION_USE_STD_VARIANT 2
++#define ABSL_OPTION_USE_STD_VARIANT 0
+ 
+ 
+ // ABSL_OPTION_USE_INLINE_NAMESPACE
diff --git a/linhes/qt5-webengine/qt5-webengine-icu-78.patch b/linhes/qt5-webengine/qt5-webengine-icu-78.patch
new file mode 100644
index 0000000..d11299c
--- /dev/null
+++ b/linhes/qt5-webengine/qt5-webengine-icu-78.patch
@@ -0,0 +1,79 @@
+https://unicode-org.github.io/icu-docs/apidoc/dev/icu4c/uchar_8h_source.html
+https://github.com/unicode-org/icu/blame/main/icu4c/source/common/unicode/uchar.h
+/usr/include/unicode/uchar.h
+
+ICU78 adds LineBreak U_LB_UNAMBIGUOUS_HYPHEN = 48,/*[HH]*/.
+U_LB_COUNT goes from 48 to 49.
+
+kBreakAllLineBreakClassTable is expected to be square with
+the same number of bits across as the lines down for every
+U_LB_COUNT LineBreak. This table should have U_LB_COUNT=49
+bit columns and 49 rows with a bunch of 1 bits sprinkled
+all over and should expand each time a new LineBreak is
+added. Rather than fiddling with the BA_LB_COUNT math or
+keep extending the table with zeros across and down as they
+did here:
+
+https://src.opensuse.org/nodejs/nodejs-electron/src/commit/ee8e43b84d0e17b17d817943357e74dee3e5474ae7e6eaff93c60926bfc3780a/text_break_iterator-icu74-breakAllLineBreakClassTable-should-be-consistent.patch
+
+we just hard set the table to 40 lines to support 0XX-39RI.
+ShouldBreakAfterBreakAll for LineBreak >= 40EB always
+return 0/false which is what the recent table patches were
+doing anyways. Look at the columns RI to VI and lines
+[RI]-[VI]. It's all zeros so everyone gave up extending
+this table with cleverly placed 1's years ago and just came
+up with Whatever Works (TM) patches. LineBreak support >=
+39RI running with 0 may be less than optimal. Here's
+another patch.
+
+https://bugs.gentoo.org/917635
+
+The original table code and patches since are all garbage
+anyways. Noone seems to understand what this table does. I
+don't either but I do know its limits and proper shape and
+that it's not required to have lines and columns added for
+each new LineBreak unless you want perfect support for new
+LineBreak.
+
+The NodeJS patch adds a 6th array column which won't
+compile on earlier ICU versions where U_LB_COUNT is small.
+
+static const unsigned char kBreakAllLineBreakClassTable[][BA_LB_COUNT / 8 + 1] = {
+
+This line is written wrong. It creates an extra byte
+column when BA_LB_COUNT is divisible by 8. Our example of
+40 LineBreak can be stored in 40/8=5 column bytes yet this
+sets the column count to 40/8+1=6. This would be correct
+though with the size of this code I don't see a problem
+allocating 40 extra bytes.
+
+static const unsigned char kBreakAllLineBreakClassTable[][(BA_LB_COUNT-1) / 8 + 1] = {
+
+severach@aur
+https://aur.archlinux.org/packages/qt5-webengine
+
+$ notepadqq
+Cannot mix incompatible Qt library (5.15.17) with this library (5.15.18)
+
+If you have trouble with an application not working, look
+through this list for packages with old versions.
+
+pacman -Qs qt5-
+
+local/qt5-base 5.15.18+kde+r109-2 (qt5)
+*   A cross-platform application and UI framework
+local/qt5-webchannel 5.15.17+kde+r3-1 (qt5)
+*   Provides access to QObject or QML objects from HTML clients for seamless integration of Qt applications with HTML/JavaScript clients
+
+diff -pNaru3 a/src/3rdparty/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc b/src/3rdparty/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc
+--- a/src/3rdparty/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc	2025-11-11 01:42:16.454081862 -0500
++++ b/src/3rdparty/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc	2025-11-11 01:49:41.838185933 -0500
+@@ -163,7 +163,7 @@ static const unsigned char kAsciiLineBre
+ // clang-format on
+ 
+ #if U_ICU_VERSION_MAJOR_NUM >= 74
+-#define BA_LB_COUNT (U_LB_COUNT - 8)
++#define BA_LB_COUNT (40) /* (U_LB_COUNT - 8) */
+ #elif U_ICU_VERSION_MAJOR_NUM >= 58
+ #define BA_LB_COUNT (U_LB_COUNT - 3)
+ #else
diff --git a/linhes/qt5-webengine/qt5-webengine-ninja-1.12.patch b/linhes/qt5-webengine/qt5-webengine-ninja-1.12.patch
new file mode 100644
index 0000000..9bddb53
--- /dev/null
+++ b/linhes/qt5-webengine/qt5-webengine-ninja-1.12.patch
@@ -0,0 +1,12 @@
+diff --git a/chromium/content/public/browser/BUILD.gn b/chromium/content/public/browser/BUILD.gn
+index 7cf82a4aacf..0e0dda2c3ca 100644
+--- a/chromium/content/public/browser/BUILD.gn
++++ b/chromium/content/public/browser/BUILD.gn
+@@ -469,6 +469,7 @@ jumbo_source_set("browser_sources") {
+     "//build:chromeos_buildflags",
+     "//cc",
+     "//components/viz/host",
++    "//components/spellcheck:buildflags",
+     "//content/browser",  # Must not be public_deps!
+     "//device/fido",
+     "//gpu",
diff --git a/linhes/qt5-webengine/qt5-webengine-pipewire-0.3.patch b/linhes/qt5-webengine/qt5-webengine-pipewire-0.3.patch
new file mode 100644
index 0000000..f8047e0
--- /dev/null
+++ b/linhes/qt5-webengine/qt5-webengine-pipewire-0.3.patch
@@ -0,0 +1,1819 @@
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/BUILD.gn b/chromium/third_party/webrtc/modules/desktop_capture/BUILD.gn
+index 5235512735d..8259442f811 100644
+--- a/chromium/third_party/webrtc/modules/desktop_capture/BUILD.gn
++++ b/chromium/third_party/webrtc/modules/desktop_capture/BUILD.gn
+@@ -11,6 +11,11 @@ import("//build/config/ui.gni")
+ import("//tools/generate_stubs/rules.gni")
+ import("../../webrtc.gni")
+ 
++if (rtc_use_pipewire) {
++  assert(rtc_pipewire_version == "0.2" || rtc_pipewire_version == "0.3",
++         "Unsupported PipeWire version")
++}
++
+ use_desktop_capture_differ_sse2 = current_cpu == "x86" || current_cpu == "x64"
+ 
+ config("x11_config") {
+@@ -200,22 +205,41 @@ if (is_linux || is_chromeos) {
+       ]
+     }
+ 
+-    if (rtc_link_pipewire) {
++    if (rtc_pipewire_version == "0.3") {
+       pkg_config("pipewire") {
+-        packages = [ "libpipewire-0.2" ]
++        packages = [ "libpipewire-0.3" ]
++        if (!rtc_link_pipewire) {
++          ignore_libs = true
++        }
+       }
+     } else {
++      pkg_config("pipewire") {
++        packages = [ "libpipewire-0.2" ]
++        if (!rtc_link_pipewire) {
++          ignore_libs = true
++        }
++      }
++    }
++
++    if (!rtc_link_pipewire) {
+       # When libpipewire is not directly linked, use stubs to allow for dlopening of
+       # the binary.
+       generate_stubs("pipewire_stubs") {
+-        configs = [ "../../:common_config" ]
++        configs = [
++          "../../:common_config",
++          ":pipewire",
++        ]
+         deps = [ "../../rtc_base" ]
+         extra_header = "linux/pipewire_stub_header.fragment"
+         logging_function = "RTC_LOG(LS_VERBOSE)"
+         logging_include = "rtc_base/logging.h"
+         output_name = "linux/pipewire_stubs"
+         path_from_source = "modules/desktop_capture/linux"
+-        sigs = [ "linux/pipewire.sigs" ]
++        if (rtc_pipewire_version == "0.3") {
++          sigs = [ "linux/pipewire03.sigs" ]
++        } else {
++          sigs = [ "linux/pipewire02.sigs" ]
++        }
+       }
+     }
+ 
+@@ -506,6 +530,7 @@ rtc_library("desktop_capture_generic") {
+   absl_deps = [
+     "//third_party/abseil-cpp/absl/memory",
+     "//third_party/abseil-cpp/absl/strings",
++    "//third_party/abseil-cpp/absl/types:optional",
+   ]
+ 
+   if (rtc_use_x11_extensions) {
+@@ -526,20 +551,15 @@ rtc_library("desktop_capture_generic") {
+     sources += [
+       "linux/base_capturer_pipewire.cc",
+       "linux/base_capturer_pipewire.h",
+-      "linux/screen_capturer_pipewire.cc",
+-      "linux/screen_capturer_pipewire.h",
+-      "linux/window_capturer_pipewire.cc",
+-      "linux/window_capturer_pipewire.h",
+     ]
+ 
+     configs += [
+       ":pipewire_config",
+       ":gio",
++      ":pipewire",
+     ]
+ 
+-    if (rtc_link_pipewire) {
+-      configs += [ ":pipewire" ]
+-    } else {
++    if (!rtc_link_pipewire) {
+       deps += [ ":pipewire_stubs" ]
+     }
+   }
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc b/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
+index 2640e93aa98..c302a086ead 100644
+--- a/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
++++ b/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
+@@ -14,8 +14,14 @@
+ #include <glib-object.h>
+ #include <spa/param/format-utils.h>
+ #include <spa/param/props.h>
++#if !PW_CHECK_VERSION(0, 3, 0)
+ #include <spa/param/video/raw-utils.h>
+ #include <spa/support/type-map.h>
++#endif
++
++#include <sys/ioctl.h>
++#include <sys/mman.h>
++#include <sys/syscall.h>
+ 
+ #include <memory>
+ #include <utility>
+@@ -30,7 +36,11 @@
+ #include "modules/desktop_capture/linux/pipewire_stubs.h"
+ 
+ using modules_desktop_capture_linux::InitializeStubs;
+-using modules_desktop_capture_linux::kModulePipewire;
++#if PW_CHECK_VERSION(0, 3, 0)
++using modules_desktop_capture_linux::kModulePipewire03;
++#else
++using modules_desktop_capture_linux::kModulePipewire02;
++#endif
+ using modules_desktop_capture_linux::StubPathMap;
+ #endif  // defined(WEBRTC_DLOPEN_PIPEWIRE)
+ 
+@@ -47,9 +57,156 @@ const char kScreenCastInterfaceName[] = "org.freedesktop.portal.ScreenCast";
+ const int kBytesPerPixel = 4;
+ 
+ #if defined(WEBRTC_DLOPEN_PIPEWIRE)
++#if PW_CHECK_VERSION(0, 3, 0)
++const char kPipeWireLib[] = "libpipewire-0.3.so.0";
++#else
+ const char kPipeWireLib[] = "libpipewire-0.2.so.1";
+ #endif
++#endif
+ 
++// static
++struct dma_buf_sync {
++  uint64_t flags;
++};
++#define DMA_BUF_SYNC_READ (1 << 0)
++#define DMA_BUF_SYNC_START (0 << 2)
++#define DMA_BUF_SYNC_END (1 << 2)
++#define DMA_BUF_BASE 'b'
++#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
++
++static void SyncDmaBuf(int fd, uint64_t start_or_end) {
++  struct dma_buf_sync sync = {0};
++
++  sync.flags = start_or_end | DMA_BUF_SYNC_READ;
++
++  while (true) {
++    int ret;
++    ret = ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync);
++    if (ret == -1 && errno == EINTR) {
++      continue;
++    } else if (ret == -1) {
++      RTC_LOG(LS_ERROR) << "Failed to synchronize DMA buffer: "
++                        << g_strerror(errno);
++      break;
++    } else {
++      break;
++    }
++  }
++}
++
++class ScopedBuf {
++ public:
++  ScopedBuf() {}
++  ScopedBuf(unsigned char* map, int map_size, bool is_dma_buf, int fd)
++      : map_(map), map_size_(map_size), is_dma_buf_(is_dma_buf), fd_(fd) {}
++  ~ScopedBuf() {
++    if (map_ != MAP_FAILED) {
++      if (is_dma_buf_) {
++        SyncDmaBuf(fd_, DMA_BUF_SYNC_END);
++      }
++      munmap(map_, map_size_);
++    }
++  }
++
++  operator bool() { return map_ != MAP_FAILED; }
++
++  void initialize(unsigned char* map, int map_size, bool is_dma_buf, int fd) {
++    map_ = map;
++    map_size_ = map_size;
++    is_dma_buf_ = is_dma_buf;
++    fd_ = fd;
++  }
++
++  unsigned char* get() { return map_; }
++
++ protected:
++  unsigned char* map_ = nullptr;
++  int map_size_;
++  bool is_dma_buf_;
++  int fd_;
++};
++
++template <class T>
++class Scoped {
++ public:
++  Scoped() {}
++  explicit Scoped(T* val) { ptr_ = val; }
++  ~Scoped() { RTC_NOTREACHED(); }
++
++  T* operator->() { return ptr_; }
++
++  bool operator!() { return ptr_ == nullptr; }
++
++  T* get() { return ptr_; }
++
++  T** receive() {
++    RTC_CHECK(!ptr_);
++    return &ptr_;
++  }
++
++  Scoped& operator=(T* val) {
++    ptr_ = val;
++    return *this;
++  }
++
++ protected:
++  T* ptr_ = nullptr;
++};
++
++template <>
++Scoped<GError>::~Scoped() {
++  if (ptr_) {
++    g_error_free(ptr_);
++  }
++}
++
++template <>
++Scoped<gchar>::~Scoped() {
++  if (ptr_) {
++    g_free(ptr_);
++  }
++}
++
++template <>
++Scoped<GVariant>::~Scoped() {
++  if (ptr_) {
++    g_variant_unref(ptr_);
++  }
++}
++
++template <>
++Scoped<GVariantIter>::~Scoped() {
++  if (ptr_) {
++    g_variant_iter_free(ptr_);
++  }
++}
++
++template <>
++Scoped<GDBusMessage>::~Scoped() {
++  if (ptr_) {
++    g_object_unref(ptr_);
++  }
++}
++
++template <>
++Scoped<GUnixFDList>::~Scoped() {
++  if (ptr_) {
++    g_object_unref(ptr_);
++  }
++}
++
++#if PW_CHECK_VERSION(0, 3, 0)
++void BaseCapturerPipeWire::OnCoreError(void* data,
++                                       uint32_t id,
++                                       int seq,
++                                       int res,
++                                       const char* message) {
++  BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
++  RTC_DCHECK(that);
++
++  RTC_LOG(LS_ERROR) << "PipeWire remote error: " << message;
++}
++#else
+ // static
+ void BaseCapturerPipeWire::OnStateChanged(void* data,
+                                           pw_remote_state old_state,
+@@ -64,7 +221,7 @@ void BaseCapturerPipeWire::OnStateChanged(void* data,
+       break;
+     case PW_REMOTE_STATE_CONNECTED:
+       RTC_LOG(LS_INFO) << "PipeWire remote state: connected.";
+-      that->CreateReceivingStream();
++      that->pw_stream_ = that->CreateReceivingStream();
+       break;
+     case PW_REMOTE_STATE_CONNECTING:
+       RTC_LOG(LS_INFO) << "PipeWire remote state: connecting.";
+@@ -74,6 +231,7 @@ void BaseCapturerPipeWire::OnStateChanged(void* data,
+       break;
+   }
+ }
++#endif
+ 
+ // static
+ void BaseCapturerPipeWire::OnStreamStateChanged(void* data,
+@@ -83,6 +241,18 @@ void BaseCapturerPipeWire::OnStreamStateChanged(void* data,
+   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
+   RTC_DCHECK(that);
+ 
++#if PW_CHECK_VERSION(0, 3, 0)
++  switch (state) {
++    case PW_STREAM_STATE_ERROR:
++      RTC_LOG(LS_ERROR) << "PipeWire stream state error: " << error_message;
++      break;
++    case PW_STREAM_STATE_PAUSED:
++    case PW_STREAM_STATE_STREAMING:
++    case PW_STREAM_STATE_UNCONNECTED:
++    case PW_STREAM_STATE_CONNECTING:
++      break;
++  }
++#else
+   switch (state) {
+     case PW_STREAM_STATE_ERROR:
+       RTC_LOG(LS_ERROR) << "PipeWire stream state error: " << error_message;
+@@ -97,36 +267,74 @@ void BaseCapturerPipeWire::OnStreamStateChanged(void* data,
+     case PW_STREAM_STATE_STREAMING:
+       break;
+   }
++#endif
+ }
+ 
+ // static
++#if PW_CHECK_VERSION(0, 3, 0)
++void BaseCapturerPipeWire::OnStreamParamChanged(void* data,
++                                                uint32_t id,
++                                                const struct spa_pod* format) {
++#else
+ void BaseCapturerPipeWire::OnStreamFormatChanged(void* data,
+                                                  const struct spa_pod* format) {
++#endif
+   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
+   RTC_DCHECK(that);
+ 
+   RTC_LOG(LS_INFO) << "PipeWire stream format changed.";
+ 
++#if PW_CHECK_VERSION(0, 3, 0)
++  if (!format || id != SPA_PARAM_Format) {
++#else
+   if (!format) {
+     pw_stream_finish_format(that->pw_stream_, /*res=*/0, /*params=*/nullptr,
+                             /*n_params=*/0);
++#endif
+     return;
+   }
+ 
++#if PW_CHECK_VERSION(0, 3, 0)
++  spa_format_video_raw_parse(format, &that->spa_video_format_);
++#else
+   that->spa_video_format_ = new spa_video_info_raw();
+   spa_format_video_raw_parse(format, that->spa_video_format_,
+                              &that->pw_type_->format_video);
++#endif
+ 
++#if PW_CHECK_VERSION(0, 3, 0)
++  auto width = that->spa_video_format_.size.width;
++  auto height = that->spa_video_format_.size.height;
++#else
+   auto width = that->spa_video_format_->size.width;
+   auto height = that->spa_video_format_->size.height;
++#endif
+   auto stride = SPA_ROUND_UP_N(width * kBytesPerPixel, 4);
+   auto size = height * stride;
+ 
++  that->desktop_size_ = DesktopSize(width, height);
++
+   uint8_t buffer[1024] = {};
+   auto builder = spa_pod_builder{buffer, sizeof(buffer)};
+ 
+   // Setup buffers and meta header for new format.
+-  const struct spa_pod* params[2];
++  const struct spa_pod* params[3];
++#if PW_CHECK_VERSION(0, 3, 0)
++  params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(
++      &builder, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
++      SPA_PARAM_BUFFERS_size, SPA_POD_Int(size), SPA_PARAM_BUFFERS_stride,
++      SPA_POD_Int(stride), SPA_PARAM_BUFFERS_buffers,
++      SPA_POD_CHOICE_RANGE_Int(8, 1, 32)));
++  params[1] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(
++      &builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_PARAM_META_type,
++      SPA_POD_Id(SPA_META_Header), SPA_PARAM_META_size,
++      SPA_POD_Int(sizeof(struct spa_meta_header))));
++  params[2] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(
++      &builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_PARAM_META_type,
++      SPA_POD_Id(SPA_META_VideoCrop), SPA_PARAM_META_size,
++      SPA_POD_Int(sizeof(struct spa_meta_region))));
++  pw_stream_update_params(that->pw_stream_, params, 3);
++#else
+   params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
+       &builder,
+       // id to enumerate buffer requirements
+@@ -155,8 +363,18 @@ void BaseCapturerPipeWire::OnStreamFormatChanged(void* data,
+       // Size: size of the metadata, specified as integer (i)
+       ":", that->pw_core_type_->param_meta.size, "i",
+       sizeof(struct spa_meta_header)));
+-
+-  pw_stream_finish_format(that->pw_stream_, /*res=*/0, params, /*n_params=*/2);
++  params[2] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
++      &builder,
++      // id to enumerate supported metadata
++      that->pw_core_type_->param.idMeta, that->pw_core_type_->param_meta.Meta,
++      // Type: specified as id or enum (I)
++      ":", that->pw_core_type_->param_meta.type, "I",
++      that->pw_core_type_->meta.VideoCrop,
++      // Size: size of the metadata, specified as integer (i)
++      ":", that->pw_core_type_->param_meta.size, "i",
++      sizeof(struct spa_meta_video_crop)));
++  pw_stream_finish_format(that->pw_stream_, /*res=*/0, params, /*n_params=*/3);
++#endif
+ }
+ 
+ // static
+@@ -164,15 +382,26 @@ void BaseCapturerPipeWire::OnStreamProcess(void* data) {
+   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
+   RTC_DCHECK(that);
+ 
+-  pw_buffer* buf = nullptr;
++  struct pw_buffer* next_buffer;
++  struct pw_buffer* buffer = nullptr;
++
++  next_buffer = pw_stream_dequeue_buffer(that->pw_stream_);
++  while (next_buffer) {
++    buffer = next_buffer;
++    next_buffer = pw_stream_dequeue_buffer(that->pw_stream_);
+ 
+-  if (!(buf = pw_stream_dequeue_buffer(that->pw_stream_))) {
++    if (next_buffer) {
++      pw_stream_queue_buffer(that->pw_stream_, buffer);
++    }
++  }
++
++  if (!buffer) {
+     return;
+   }
+ 
+-  that->HandleBuffer(buf);
++  that->HandleBuffer(buffer);
+ 
+-  pw_stream_queue_buffer(that->pw_stream_, buf);
++  pw_stream_queue_buffer(that->pw_stream_, buffer);
+ }
+ 
+ BaseCapturerPipeWire::BaseCapturerPipeWire(CaptureSourceType source_type)
+@@ -183,6 +412,7 @@ BaseCapturerPipeWire::~BaseCapturerPipeWire() {
+     pw_thread_loop_stop(pw_main_loop_);
+   }
+ 
++#if !PW_CHECK_VERSION(0, 3, 0)
+   if (pw_type_) {
+     delete pw_type_;
+   }
+@@ -190,30 +420,41 @@ BaseCapturerPipeWire::~BaseCapturerPipeWire() {
+   if (spa_video_format_) {
+     delete spa_video_format_;
+   }
++#endif
+ 
+   if (pw_stream_) {
+     pw_stream_destroy(pw_stream_);
+   }
+ 
++#if !PW_CHECK_VERSION(0, 3, 0)
+   if (pw_remote_) {
+     pw_remote_destroy(pw_remote_);
+   }
++#endif
+ 
++#if PW_CHECK_VERSION(0, 3, 0)
++  if (pw_core_) {
++    pw_core_disconnect(pw_core_);
++  }
++
++  if (pw_context_) {
++    pw_context_destroy(pw_context_);
++  }
++#else
+   if (pw_core_) {
+     pw_core_destroy(pw_core_);
+   }
++#endif
+ 
+   if (pw_main_loop_) {
+     pw_thread_loop_destroy(pw_main_loop_);
+   }
+ 
++#if !PW_CHECK_VERSION(0, 3, 0)
+   if (pw_loop_) {
+     pw_loop_destroy(pw_loop_);
+   }
+-
+-  if (current_frame_) {
+-    free(current_frame_);
+-  }
++#endif
+ 
+   if (start_request_signal_id_) {
+     g_dbus_connection_signal_unsubscribe(connection_, start_request_signal_id_);
+@@ -228,18 +469,16 @@ BaseCapturerPipeWire::~BaseCapturerPipeWire() {
+   }
+ 
+   if (session_handle_) {
+-    GDBusMessage* message = g_dbus_message_new_method_call(
+-        kDesktopBusName, session_handle_, kSessionInterfaceName, "Close");
+-    if (message) {
+-      GError* error = nullptr;
+-      g_dbus_connection_send_message(connection_, message,
++    Scoped<GDBusMessage> message(g_dbus_message_new_method_call(
++        kDesktopBusName, session_handle_, kSessionInterfaceName, "Close"));
++    if (message.get()) {
++      Scoped<GError> error;
++      g_dbus_connection_send_message(connection_, message.get(),
+                                      G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+-                                     /*out_serial=*/nullptr, &error);
+-      if (error) {
++                                     /*out_serial=*/nullptr, error.receive());
++      if (error.get()) {
+         RTC_LOG(LS_ERROR) << "Failed to close the session: " << error->message;
+-        g_error_free(error);
+       }
+-      g_object_unref(message);
+     }
+   }
+ 
+@@ -274,7 +513,11 @@ void BaseCapturerPipeWire::InitPipeWire() {
+   StubPathMap paths;
+ 
+   // Check if the PipeWire library is available.
+-  paths[kModulePipewire].push_back(kPipeWireLib);
++#if PW_CHECK_VERSION(0, 3, 0)
++  paths[kModulePipewire03].push_back(kPipeWireLib);
++#else
++  paths[kModulePipewire02].push_back(kPipeWireLib);
++#endif
+   if (!InitializeStubs(paths)) {
+     RTC_LOG(LS_ERROR) << "Failed to load the PipeWire library and symbols.";
+     portal_init_failed_ = true;
+@@ -284,16 +527,46 @@ void BaseCapturerPipeWire::InitPipeWire() {
+ 
+   pw_init(/*argc=*/nullptr, /*argc=*/nullptr);
+ 
++#if PW_CHECK_VERSION(0, 3, 0)
++  pw_main_loop_ = pw_thread_loop_new("pipewire-main-loop", nullptr);
++
++  pw_thread_loop_lock(pw_main_loop_);
++
++  pw_context_ =
++      pw_context_new(pw_thread_loop_get_loop(pw_main_loop_), nullptr, 0);
++  if (!pw_context_) {
++    RTC_LOG(LS_ERROR) << "Failed to create PipeWire context";
++    return;
++  }
++
++  pw_core_ = pw_context_connect(pw_context_, nullptr, 0);
++  if (!pw_core_) {
++    RTC_LOG(LS_ERROR) << "Failed to connect PipeWire context";
++    return;
++  }
++#else
+   pw_loop_ = pw_loop_new(/*properties=*/nullptr);
+   pw_main_loop_ = pw_thread_loop_new(pw_loop_, "pipewire-main-loop");
+ 
++  pw_thread_loop_lock(pw_main_loop_);
++
+   pw_core_ = pw_core_new(pw_loop_, /*properties=*/nullptr);
+   pw_core_type_ = pw_core_get_type(pw_core_);
+   pw_remote_ = pw_remote_new(pw_core_, nullptr, /*user_data_size=*/0);
+ 
+   InitPipeWireTypes();
++#endif
+ 
+   // Initialize event handlers, remote end and stream-related.
++#if PW_CHECK_VERSION(0, 3, 0)
++  pw_core_events_.version = PW_VERSION_CORE_EVENTS;
++  pw_core_events_.error = &OnCoreError;
++
++  pw_stream_events_.version = PW_VERSION_STREAM_EVENTS;
++  pw_stream_events_.state_changed = &OnStreamStateChanged;
++  pw_stream_events_.param_changed = &OnStreamParamChanged;
++  pw_stream_events_.process = &OnStreamProcess;
++#else
+   pw_remote_events_.version = PW_VERSION_REMOTE_EVENTS;
+   pw_remote_events_.state_changed = &OnStateChanged;
+ 
+@@ -301,19 +574,33 @@ void BaseCapturerPipeWire::InitPipeWire() {
+   pw_stream_events_.state_changed = &OnStreamStateChanged;
+   pw_stream_events_.format_changed = &OnStreamFormatChanged;
+   pw_stream_events_.process = &OnStreamProcess;
++#endif
+ 
++#if PW_CHECK_VERSION(0, 3, 0)
++  pw_core_add_listener(pw_core_, &spa_core_listener_, &pw_core_events_, this);
++
++  pw_stream_ = CreateReceivingStream();
++  if (!pw_stream_) {
++    RTC_LOG(LS_ERROR) << "Failed to create PipeWire stream";
++    return;
++  }
++#else
+   pw_remote_add_listener(pw_remote_, &spa_remote_listener_, &pw_remote_events_,
+                          this);
+   pw_remote_connect_fd(pw_remote_, pw_fd_);
++#endif
+ 
+   if (pw_thread_loop_start(pw_main_loop_) < 0) {
+     RTC_LOG(LS_ERROR) << "Failed to start main PipeWire loop";
+     portal_init_failed_ = true;
+   }
+ 
++  pw_thread_loop_unlock(pw_main_loop_);
++
+   RTC_LOG(LS_INFO) << "PipeWire remote opened.";
+ }
+ 
++#if !PW_CHECK_VERSION(0, 3, 0)
+ void BaseCapturerPipeWire::InitPipeWireTypes() {
+   spa_type_map* map = pw_core_type_->map;
+   pw_type_ = new PipeWireType();
+@@ -323,23 +610,44 @@ void BaseCapturerPipeWire::InitPipeWireTypes() {
+   spa_type_format_video_map(map, &pw_type_->format_video);
+   spa_type_video_format_map(map, &pw_type_->video_format);
+ }
++#endif
+ 
+-void BaseCapturerPipeWire::CreateReceivingStream() {
++pw_stream* BaseCapturerPipeWire::CreateReceivingStream() {
++#if !PW_CHECK_VERSION(0, 3, 0)
++  if (pw_remote_get_state(pw_remote_, nullptr) != PW_REMOTE_STATE_CONNECTED) {
++    RTC_LOG(LS_ERROR) << "Cannot create pipewire stream";
++    return nullptr;
++  }
++#endif
+   spa_rectangle pwMinScreenBounds = spa_rectangle{1, 1};
+-  spa_rectangle pwScreenBounds =
+-      spa_rectangle{static_cast<uint32_t>(desktop_size_.width()),
+-                    static_cast<uint32_t>(desktop_size_.height())};
+-
+-  spa_fraction pwFrameRateMin = spa_fraction{0, 1};
+-  spa_fraction pwFrameRateMax = spa_fraction{60, 1};
++  spa_rectangle pwMaxScreenBounds = spa_rectangle{UINT32_MAX, UINT32_MAX};
+ 
+   pw_properties* reuseProps =
+       pw_properties_new_string("pipewire.client.reuse=1");
+-  pw_stream_ = pw_stream_new(pw_remote_, "webrtc-consume-stream", reuseProps);
++#if PW_CHECK_VERSION(0, 3, 0)
++  auto stream = pw_stream_new(pw_core_, "webrtc-consume-stream", reuseProps);
++#else
++  auto stream = pw_stream_new(pw_remote_, "webrtc-consume-stream", reuseProps);
++#endif
+ 
+   uint8_t buffer[1024] = {};
+   const spa_pod* params[1];
+   spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)};
++
++#if PW_CHECK_VERSION(0, 3, 0)
++  params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(
++      &builder, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
++      SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
++      SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
++      SPA_FORMAT_VIDEO_format,
++      SPA_POD_CHOICE_ENUM_Id(5, SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx,
++                             SPA_VIDEO_FORMAT_RGBA, SPA_VIDEO_FORMAT_BGRx,
++                             SPA_VIDEO_FORMAT_BGRA),
++      SPA_FORMAT_VIDEO_size,
++      SPA_POD_CHOICE_RANGE_Rectangle(&pwMinScreenBounds, &pwMinScreenBounds,
++                                     &pwMaxScreenBounds),
++      0));
++#else
+   params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
+       &builder,
+       // id to enumerate formats
+@@ -349,69 +657,218 @@ void BaseCapturerPipeWire::CreateReceivingStream() {
+       // then allowed formats are enumerated (e) and the format is undecided (u)
+       // to allow negotiation
+       ":", pw_type_->format_video.format, "Ieu", pw_type_->video_format.BGRx,
+-      SPA_POD_PROP_ENUM(2, pw_type_->video_format.RGBx,
+-                        pw_type_->video_format.BGRx),
++      SPA_POD_PROP_ENUM(
++          4, pw_type_->video_format.RGBx, pw_type_->video_format.BGRx,
++          pw_type_->video_format.RGBA, pw_type_->video_format.BGRA),
+       // Video size: specified as rectangle (R), preferred size is specified as
+       // first parameter, then allowed size is defined as range (r) from min and
+       // max values and the format is undecided (u) to allow negotiation
+-      ":", pw_type_->format_video.size, "Rru", &pwScreenBounds, 2,
+-      &pwMinScreenBounds, &pwScreenBounds,
+-      // Frame rate: specified as fraction (F) and set to minimum frame rate
+-      // value
+-      ":", pw_type_->format_video.framerate, "F", &pwFrameRateMin,
+-      // Max frame rate: specified as fraction (F), preferred frame rate is set
+-      // to maximum value, then allowed frame rate is defined as range (r) from
+-      // min and max values and it is undecided (u) to allow negotiation
+-      ":", pw_type_->format_video.max_framerate, "Fru", &pwFrameRateMax, 2,
+-      &pwFrameRateMin, &pwFrameRateMax));
+-
+-  pw_stream_add_listener(pw_stream_, &spa_stream_listener_, &pw_stream_events_,
++      ":", pw_type_->format_video.size, "Rru", &pwMinScreenBounds,
++      SPA_POD_PROP_MIN_MAX(&pwMinScreenBounds, &pwMaxScreenBounds)));
++#endif
++
++  pw_stream_add_listener(stream, &spa_stream_listener_, &pw_stream_events_,
+                          this);
++#if PW_CHECK_VERSION(0, 3, 0)
++  if (pw_stream_connect(stream, PW_DIRECTION_INPUT, pw_stream_node_id_,
++                        PW_STREAM_FLAG_AUTOCONNECT, params, 1) != 0) {
++#else
+   pw_stream_flags flags = static_cast<pw_stream_flags>(
+-      PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE |
+-      PW_STREAM_FLAG_MAP_BUFFERS);
+-  if (pw_stream_connect(pw_stream_, PW_DIRECTION_INPUT, /*port_path=*/nullptr,
++      PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE);
++  if (pw_stream_connect(stream, PW_DIRECTION_INPUT, /*port_path=*/nullptr,
+                         flags, params,
+                         /*n_params=*/1) != 0) {
++#endif
+     RTC_LOG(LS_ERROR) << "Could not connect receiving stream.";
+     portal_init_failed_ = true;
+-    return;
++    return nullptr;
+   }
++
++  return stream;
+ }
+ 
+ void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) {
+   spa_buffer* spaBuffer = buffer->buffer;
+-  void* src = nullptr;
++  ScopedBuf map;
++  uint8_t* src = nullptr;
++
++  if (spaBuffer->datas[0].chunk->size == 0) {
++    RTC_LOG(LS_ERROR) << "Failed to get video stream: Zero size.";
++    return;
++  }
++
++#if PW_CHECK_VERSION(0, 3, 0)
++  if (spaBuffer->datas[0].type == SPA_DATA_MemFd ||
++      spaBuffer->datas[0].type == SPA_DATA_DmaBuf) {
++#else
++  if (spaBuffer->datas[0].type == pw_core_type_->data.MemFd ||
++      spaBuffer->datas[0].type == pw_core_type_->data.DmaBuf) {
++#endif
++    map.initialize(
++        static_cast<uint8_t*>(
++            mmap(nullptr,
++                 spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
++                 PROT_READ, MAP_PRIVATE, spaBuffer->datas[0].fd, 0)),
++        spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
++#if PW_CHECK_VERSION(0, 3, 0)
++        spaBuffer->datas[0].type == SPA_DATA_DmaBuf,
++#else
++        spaBuffer->datas[0].type == pw_core_type_->data.DmaBuf,
++#endif
++        spaBuffer->datas[0].fd);
++
++    if (!map) {
++      RTC_LOG(LS_ERROR) << "Failed to mmap the memory: "
++                        << std::strerror(errno);
++      return;
++    }
++
++#if PW_CHECK_VERSION(0, 3, 0)
++    if (spaBuffer->datas[0].type == SPA_DATA_DmaBuf) {
++#else
++    if (spaBuffer->datas[0].type == pw_core_type_->data.DmaBuf) {
++#endif
++      SyncDmaBuf(spaBuffer->datas[0].fd, DMA_BUF_SYNC_START);
++    }
++
++    src = SPA_MEMBER(map.get(), spaBuffer->datas[0].mapoffset, uint8_t);
++#if PW_CHECK_VERSION(0, 3, 0)
++  } else if (spaBuffer->datas[0].type == SPA_DATA_MemPtr) {
++#else
++  } else if (spaBuffer->datas[0].type == pw_core_type_->data.MemPtr) {
++#endif
++    src = static_cast<uint8_t*>(spaBuffer->datas[0].data);
++  }
+ 
+-  if (!(src = spaBuffer->datas[0].data)) {
++  if (!src) {
++    return;
++  }
++
++#if PW_CHECK_VERSION(0, 3, 0)
++  struct spa_meta_region* video_metadata =
++      static_cast<struct spa_meta_region*>(spa_buffer_find_meta_data(
++          spaBuffer, SPA_META_VideoCrop, sizeof(*video_metadata)));
++#else
++  struct spa_meta_video_crop* video_metadata =
++      static_cast<struct spa_meta_video_crop*>(
++          spa_buffer_find_meta(spaBuffer, pw_core_type_->meta.VideoCrop));
++#endif
++
++  // Video size from metadata is bigger than an actual video stream size.
++  // The metadata are wrong or we should up-scale the video...in both cases
++  // just quit now.
++#if PW_CHECK_VERSION(0, 3, 0)
++  if (video_metadata && (video_metadata->region.size.width >
++                             static_cast<uint32_t>(desktop_size_.width()) ||
++                         video_metadata->region.size.height >
++                             static_cast<uint32_t>(desktop_size_.height()))) {
++#else
++  if (video_metadata && (video_metadata->width > desktop_size_.width() ||
++                         video_metadata->height > desktop_size_.height())) {
++#endif
++    RTC_LOG(LS_ERROR) << "Stream metadata sizes are wrong!";
+     return;
+   }
+ 
+-  uint32_t maxSize = spaBuffer->datas[0].maxsize;
+-  int32_t srcStride = spaBuffer->datas[0].chunk->stride;
+-  if (srcStride != (desktop_size_.width() * kBytesPerPixel)) {
++  // Use video metadata when video size from metadata is set and smaller than
++  // video stream size, so we need to adjust it.
++  bool video_is_full_width = true;
++  bool video_is_full_height = true;
++#if PW_CHECK_VERSION(0, 3, 0)
++  if (video_metadata && video_metadata->region.size.width != 0 &&
++      video_metadata->region.size.height != 0) {
++    if (video_metadata->region.size.width <
++        static_cast<uint32_t>(desktop_size_.width())) {
++      video_is_full_width = false;
++    } else if (video_metadata->region.size.height <
++               static_cast<uint32_t>(desktop_size_.height())) {
++      video_is_full_height = false;
++    }
++  }
++#else
++  if (video_metadata && video_metadata->width != 0 &&
++      video_metadata->height != 0) {
++    if (video_metadata->width < desktop_size_.width()) {
++    } else if (video_metadata->height < desktop_size_.height()) {
++      video_is_full_height = false;
++    }
++  }
++#endif
++
++  DesktopSize video_size_prev = video_size_;
++  if (!video_is_full_height || !video_is_full_width) {
++#if PW_CHECK_VERSION(0, 3, 0)
++    video_size_ = DesktopSize(video_metadata->region.size.width,
++                              video_metadata->region.size.height);
++#else
++    video_size_ = DesktopSize(video_metadata->width, video_metadata->height);
++#endif
++  } else {
++    video_size_ = desktop_size_;
++  }
++
++  webrtc::MutexLock lock(&current_frame_lock_);
++  if (!current_frame_ || !video_size_.equals(video_size_prev)) {
++    current_frame_ = std::make_unique<uint8_t[]>(
++        video_size_.width() * video_size_.height() * kBytesPerPixel);
++  }
++
++  const int32_t dst_stride = video_size_.width() * kBytesPerPixel;
++  const int32_t src_stride = spaBuffer->datas[0].chunk->stride;
++
++  if (src_stride != (desktop_size_.width() * kBytesPerPixel)) {
+     RTC_LOG(LS_ERROR) << "Got buffer with stride different from screen stride: "
+-                      << srcStride
++                      << src_stride
+                       << " != " << (desktop_size_.width() * kBytesPerPixel);
+     portal_init_failed_ = true;
++
+     return;
+   }
+ 
+-  if (!current_frame_) {
+-    current_frame_ = static_cast<uint8_t*>(malloc(maxSize));
+-  }
+-  RTC_DCHECK(current_frame_ != nullptr);
+-
+-  // If both sides decided to go with the RGBx format we need to convert it to
+-  // BGRx to match color format expected by WebRTC.
+-  if (spa_video_format_->format == pw_type_->video_format.RGBx) {
+-    uint8_t* tempFrame = static_cast<uint8_t*>(malloc(maxSize));
+-    std::memcpy(tempFrame, src, maxSize);
+-    ConvertRGBxToBGRx(tempFrame, maxSize);
+-    std::memcpy(current_frame_, tempFrame, maxSize);
+-    free(tempFrame);
+-  } else {
+-    std::memcpy(current_frame_, src, maxSize);
++  // Adjust source content based on metadata video position
++#if PW_CHECK_VERSION(0, 3, 0)
++  if (!video_is_full_height &&
++      (video_metadata->region.position.y + video_size_.height() <=
++       desktop_size_.height())) {
++    src += src_stride * video_metadata->region.position.y;
++  }
++  const int x_offset =
++      !video_is_full_width &&
++              (video_metadata->region.position.x + video_size_.width() <=
++               desktop_size_.width())
++          ? video_metadata->region.position.x * kBytesPerPixel
++          : 0;
++#else
++  if (!video_is_full_height &&
++      (video_metadata->y + video_size_.height() <= desktop_size_.height())) {
++    src += src_stride * video_metadata->y;
++  }
++
++  const int x_offset =
++      !video_is_full_width &&
++              (video_metadata->x + video_size_.width() <= desktop_size_.width())
++          ? video_metadata->x * kBytesPerPixel
++          : 0;
++#endif
++
++  uint8_t* dst = current_frame_.get();
++  for (int i = 0; i < video_size_.height(); ++i) {
++    // Adjust source content based on crop video position if needed
++    src += x_offset;
++    std::memcpy(dst, src, dst_stride);
++    // If both sides decided to go with the RGBx format we need to convert it to
++    // BGRx to match color format expected by WebRTC.
++#if PW_CHECK_VERSION(0, 3, 0)
++    if (spa_video_format_.format == SPA_VIDEO_FORMAT_RGBx ||
++        spa_video_format_.format == SPA_VIDEO_FORMAT_RGBA) {
++#else
++    if (spa_video_format_->format == pw_type_->video_format.RGBx ||
++        spa_video_format_->format == pw_type_->video_format.RGBA) {
++#endif
++      ConvertRGBxToBGRx(dst, dst_stride);
++    }
++    src += src_stride - x_offset;
++    dst += dst_stride;
+   }
+ }
+ 
+@@ -441,14 +898,13 @@ void BaseCapturerPipeWire::OnProxyRequested(GObject* /*object*/,
+   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data);
+   RTC_DCHECK(that);
+ 
+-  GError* error = nullptr;
+-  GDBusProxy *proxy = g_dbus_proxy_new_finish(result, &error);
++  Scoped<GError> error;
++  GDBusProxy* proxy = g_dbus_proxy_new_finish(result, error.receive());
+   if (!proxy) {
+-    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
++    if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
+       return;
+     RTC_LOG(LS_ERROR) << "Failed to create a proxy for the screen cast portal: "
+                       << error->message;
+-    g_error_free(error);
+     that->portal_init_failed_ = true;
+     return;
+   }
+@@ -462,38 +918,36 @@ void BaseCapturerPipeWire::OnProxyRequested(GObject* /*object*/,
+ // static
+ gchar* BaseCapturerPipeWire::PrepareSignalHandle(GDBusConnection* connection,
+                                                  const gchar* token) {
+-  gchar* sender = g_strdup(g_dbus_connection_get_unique_name(connection) + 1);
+-  for (int i = 0; sender[i]; i++) {
+-    if (sender[i] == '.') {
+-      sender[i] = '_';
++  Scoped<gchar> sender(
++      g_strdup(g_dbus_connection_get_unique_name(connection) + 1));
++  for (int i = 0; sender.get()[i]; i++) {
++    if (sender.get()[i] == '.') {
++      sender.get()[i] = '_';
+     }
+   }
+ 
+-  gchar* handle = g_strconcat(kDesktopRequestObjectPath, "/", sender, "/",
++  gchar* handle = g_strconcat(kDesktopRequestObjectPath, "/", sender.get(), "/",
+                               token, /*end of varargs*/ nullptr);
+-  g_free(sender);
+ 
+   return handle;
+ }
+ 
+ void BaseCapturerPipeWire::SessionRequest() {
+   GVariantBuilder builder;
+-  gchar* variant_string;
++  Scoped<gchar> variant_string;
+ 
+   g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+   variant_string =
+       g_strdup_printf("webrtc_session%d", g_random_int_range(0, G_MAXINT));
+   g_variant_builder_add(&builder, "{sv}", "session_handle_token",
+-                        g_variant_new_string(variant_string));
+-  g_free(variant_string);
++                        g_variant_new_string(variant_string.get()));
+   variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT));
+   g_variant_builder_add(&builder, "{sv}", "handle_token",
+-                        g_variant_new_string(variant_string));
++                        g_variant_new_string(variant_string.get()));
+ 
+-  portal_handle_ = PrepareSignalHandle(connection_, variant_string);
++  portal_handle_ = PrepareSignalHandle(connection_, variant_string.get());
+   session_request_signal_id_ = SetupRequestResponseSignal(
+       portal_handle_, OnSessionRequestResponseSignal);
+-  g_free(variant_string);
+ 
+   RTC_LOG(LS_INFO) << "Screen cast session requested.";
+   g_dbus_proxy_call(
+@@ -509,22 +963,21 @@ void BaseCapturerPipeWire::OnSessionRequested(GDBusProxy *proxy,
+   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data);
+   RTC_DCHECK(that);
+ 
+-  GError* error = nullptr;
+-  GVariant* variant = g_dbus_proxy_call_finish(proxy, result, &error);
++  Scoped<GError> error;
++  Scoped<GVariant> variant(
++      g_dbus_proxy_call_finish(proxy, result, error.receive()));
+   if (!variant) {
+-    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
++    if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
+       return;
+     RTC_LOG(LS_ERROR) << "Failed to create a screen cast session: "
+                       << error->message;
+-    g_error_free(error);
+     that->portal_init_failed_ = true;
+     return;
+   }
+   RTC_LOG(LS_INFO) << "Initializing the screen cast session.";
+ 
+-  gchar* handle = nullptr;
+-  g_variant_get_child(variant, 0, "o", &handle);
+-  g_variant_unref(variant);
++  Scoped<gchar> handle;
++  g_variant_get_child(variant.get(), 0, "o", &handle);
+   if (!handle) {
+     RTC_LOG(LS_ERROR) << "Failed to initialize the screen cast session.";
+     if (that->session_request_signal_id_) {
+@@ -536,8 +989,6 @@ void BaseCapturerPipeWire::OnSessionRequested(GDBusProxy *proxy,
+     return;
+   }
+ 
+-  g_free(handle);
+-
+   RTC_LOG(LS_INFO) << "Subscribing to the screen cast session.";
+ }
+ 
+@@ -557,11 +1008,11 @@ void BaseCapturerPipeWire::OnSessionRequestResponseSignal(
+       << "Received response for the screen cast session subscription.";
+ 
+   guint32 portal_response;
+-  GVariant* response_data;
+-  g_variant_get(parameters, "(u@a{sv})", &portal_response, &response_data);
+-  g_variant_lookup(response_data, "session_handle", "s",
++  Scoped<GVariant> response_data;
++  g_variant_get(parameters, "(u@a{sv})", &portal_response,
++                response_data.receive());
++  g_variant_lookup(response_data.get(), "session_handle", "s",
+                    &that->session_handle_);
+-  g_variant_unref(response_data);
+ 
+   if (!that->session_handle_ || portal_response) {
+     RTC_LOG(LS_ERROR)
+@@ -575,23 +1026,23 @@ void BaseCapturerPipeWire::OnSessionRequestResponseSignal(
+ 
+ void BaseCapturerPipeWire::SourcesRequest() {
+   GVariantBuilder builder;
+-  gchar* variant_string;
++  Scoped<gchar> variant_string;
+ 
+   g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+   // We want to record monitor content.
+-  g_variant_builder_add(&builder, "{sv}", "types",
+-                        g_variant_new_uint32(capture_source_type_));
++  g_variant_builder_add(
++      &builder, "{sv}", "types",
++      g_variant_new_uint32(static_cast<uint32_t>(capture_source_type_)));
+   // We don't want to allow selection of multiple sources.
+   g_variant_builder_add(&builder, "{sv}", "multiple",
+                         g_variant_new_boolean(false));
+   variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT));
+   g_variant_builder_add(&builder, "{sv}", "handle_token",
+-                        g_variant_new_string(variant_string));
++                        g_variant_new_string(variant_string.get()));
+ 
+-  sources_handle_ = PrepareSignalHandle(connection_, variant_string);
++  sources_handle_ = PrepareSignalHandle(connection_, variant_string.get());
+   sources_request_signal_id_ = SetupRequestResponseSignal(
+       sources_handle_, OnSourcesRequestResponseSignal);
+-  g_free(variant_string);
+ 
+   RTC_LOG(LS_INFO) << "Requesting sources from the screen cast session.";
+   g_dbus_proxy_call(
+@@ -608,22 +1059,21 @@ void BaseCapturerPipeWire::OnSourcesRequested(GDBusProxy *proxy,
+   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data);
+   RTC_DCHECK(that);
+ 
+-  GError* error = nullptr;
+-  GVariant* variant = g_dbus_proxy_call_finish(proxy, result, &error);
++  Scoped<GError> error;
++  Scoped<GVariant> variant(
++      g_dbus_proxy_call_finish(proxy, result, error.receive()));
+   if (!variant) {
+-    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
++    if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
+       return;
+     RTC_LOG(LS_ERROR) << "Failed to request the sources: " << error->message;
+-    g_error_free(error);
+     that->portal_init_failed_ = true;
+     return;
+   }
+ 
+   RTC_LOG(LS_INFO) << "Sources requested from the screen cast session.";
+ 
+-  gchar* handle = nullptr;
+-  g_variant_get_child(variant, 0, "o", &handle);
+-  g_variant_unref(variant);
++  Scoped<gchar> handle;
++  g_variant_get_child(variant.get(), 0, "o", handle.receive());
+   if (!handle) {
+     RTC_LOG(LS_ERROR) << "Failed to initialize the screen cast session.";
+     if (that->sources_request_signal_id_) {
+@@ -635,8 +1085,6 @@ void BaseCapturerPipeWire::OnSourcesRequested(GDBusProxy *proxy,
+     return;
+   }
+ 
+-  g_free(handle);
+-
+   RTC_LOG(LS_INFO) << "Subscribed to sources signal.";
+ }
+ 
+@@ -668,17 +1116,16 @@ void BaseCapturerPipeWire::OnSourcesRequestResponseSignal(
+ 
+ void BaseCapturerPipeWire::StartRequest() {
+   GVariantBuilder builder;
+-  gchar* variant_string;
++  Scoped<gchar> variant_string;
+ 
+   g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+   variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT));
+   g_variant_builder_add(&builder, "{sv}", "handle_token",
+-                        g_variant_new_string(variant_string));
++                        g_variant_new_string(variant_string.get()));
+ 
+-  start_handle_ = PrepareSignalHandle(connection_, variant_string);
++  start_handle_ = PrepareSignalHandle(connection_, variant_string.get());
+   start_request_signal_id_ =
+       SetupRequestResponseSignal(start_handle_, OnStartRequestResponseSignal);
+-  g_free(variant_string);
+ 
+   // "Identifier for the application window", this is Wayland, so not "x11:...".
+   const gchar parent_window[] = "";
+@@ -698,23 +1145,22 @@ void BaseCapturerPipeWire::OnStartRequested(GDBusProxy *proxy,
+   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data);
+   RTC_DCHECK(that);
+ 
+-  GError* error = nullptr;
+-  GVariant* variant = g_dbus_proxy_call_finish(proxy, result, &error);
++  Scoped<GError> error;
++  Scoped<GVariant> variant(
++      g_dbus_proxy_call_finish(proxy, result, error.receive()));
+   if (!variant) {
+-    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
++    if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
+       return;
+     RTC_LOG(LS_ERROR) << "Failed to start the screen cast session: "
+                       << error->message;
+-    g_error_free(error);
+     that->portal_init_failed_ = true;
+     return;
+   }
+ 
+   RTC_LOG(LS_INFO) << "Initializing the start of the screen cast session.";
+ 
+-  gchar* handle = nullptr;
+-  g_variant_get_child(variant, 0, "o", &handle);
+-  g_variant_unref(variant);
++  Scoped<gchar> handle;
++  g_variant_get_child(variant.get(), 0, "o", handle.receive());
+   if (!handle) {
+     RTC_LOG(LS_ERROR)
+         << "Failed to initialize the start of the screen cast session.";
+@@ -727,8 +1173,6 @@ void BaseCapturerPipeWire::OnStartRequested(GDBusProxy *proxy,
+     return;
+   }
+ 
+-  g_free(handle);
+-
+   RTC_LOG(LS_INFO) << "Subscribed to the start signal.";
+ }
+ 
+@@ -746,9 +1190,10 @@ void BaseCapturerPipeWire::OnStartRequestResponseSignal(
+ 
+   RTC_LOG(LS_INFO) << "Start signal received.";
+   guint32 portal_response;
+-  GVariant* response_data;
+-  GVariantIter* iter = nullptr;
+-  g_variant_get(parameters, "(u@a{sv})", &portal_response, &response_data);
++  Scoped<GVariant> response_data;
++  Scoped<GVariantIter> iter;
++  g_variant_get(parameters, "(u@a{sv})", &portal_response,
++                response_data.receive());
+   if (portal_response || !response_data) {
+     RTC_LOG(LS_ERROR) << "Failed to start the screen cast session.";
+     that->portal_init_failed_ = true;
+@@ -758,28 +1203,28 @@ void BaseCapturerPipeWire::OnStartRequestResponseSignal(
+   // Array of PipeWire streams. See
+   // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml
+   // documentation for <method name="Start">.
+-  if (g_variant_lookup(response_data, "streams", "a(ua{sv})", &iter)) {
+-    GVariant* variant;
++  if (g_variant_lookup(response_data.get(), "streams", "a(ua{sv})",
++                       iter.receive())) {
++    Scoped<GVariant> variant;
+ 
+-    while (g_variant_iter_next(iter, "@(ua{sv})", &variant)) {
++    while (g_variant_iter_next(iter.get(), "@(ua{sv})", variant.receive())) {
+       guint32 stream_id;
+-      gint32 width;
+-      gint32 height;
+-      GVariant* options;
++      guint32 type;
++      Scoped<GVariant> options;
+ 
+-      g_variant_get(variant, "(u@a{sv})", &stream_id, &options);
+-      RTC_DCHECK(options != nullptr);
++      g_variant_get(variant.get(), "(u@a{sv})", &stream_id, options.receive());
++      RTC_DCHECK(options.get());
+ 
+-      g_variant_lookup(options, "size", "(ii)", &width, &height);
++      if (g_variant_lookup(options.get(), "source_type", "u", &type)) {
++        that->capture_source_type_ =
++            static_cast<BaseCapturerPipeWire::CaptureSourceType>(type);
++      }
+ 
+-      that->desktop_size_.set(width, height);
++      that->pw_stream_node_id_ = stream_id;
+ 
+-      g_variant_unref(options);
+-      g_variant_unref(variant);
++      break;
+     }
+   }
+-  g_variant_iter_free(iter);
+-  g_variant_unref(response_data);
+ 
+   that->OpenPipeWireRemote();
+ }
+@@ -807,35 +1252,30 @@ void BaseCapturerPipeWire::OnOpenPipeWireRemoteRequested(
+   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data);
+   RTC_DCHECK(that);
+ 
+-  GError* error = nullptr;
+-  GUnixFDList* outlist = nullptr;
+-  GVariant* variant = g_dbus_proxy_call_with_unix_fd_list_finish(
+-      proxy, &outlist, result, &error);
++  Scoped<GError> error;
++  Scoped<GUnixFDList> outlist;
++  Scoped<GVariant> variant(g_dbus_proxy_call_with_unix_fd_list_finish(
++      proxy, outlist.receive(), result, error.receive()));
+   if (!variant) {
+-    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
++    if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
+       return;
+     RTC_LOG(LS_ERROR) << "Failed to open the PipeWire remote: "
+                       << error->message;
+-    g_error_free(error);
+     that->portal_init_failed_ = true;
+     return;
+   }
+ 
+   gint32 index;
+-  g_variant_get(variant, "(h)", &index);
++  g_variant_get(variant.get(), "(h)", &index);
+ 
+-  if ((that->pw_fd_ = g_unix_fd_list_get(outlist, index, &error)) == -1) {
++  if ((that->pw_fd_ =
++           g_unix_fd_list_get(outlist.get(), index, error.receive())) == -1) {
+     RTC_LOG(LS_ERROR) << "Failed to get file descriptor from the list: "
+                       << error->message;
+-    g_error_free(error);
+-    g_variant_unref(variant);
+     that->portal_init_failed_ = true;
+     return;
+   }
+ 
+-  g_variant_unref(variant);
+-  g_object_unref(outlist);
+-
+   that->InitPipeWire();
+ }
+ 
+@@ -854,15 +1294,18 @@ void BaseCapturerPipeWire::CaptureFrame() {
+     return;
+   }
+ 
++  webrtc::MutexLock lock(&current_frame_lock_);
+   if (!current_frame_) {
+     callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
+     return;
+   }
+ 
+-  std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(desktop_size_));
++  DesktopSize frame_size = video_size_;
++
++  std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(frame_size));
+   result->CopyPixelsFrom(
+-      current_frame_, (desktop_size_.width() * kBytesPerPixel),
+-      DesktopRect::MakeWH(desktop_size_.width(), desktop_size_.height()));
++      current_frame_.get(), (frame_size.width() * kBytesPerPixel),
++      DesktopRect::MakeWH(frame_size.width(), frame_size.height()));
+   if (!result) {
+     callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
+     return;
+@@ -887,4 +1330,11 @@ bool BaseCapturerPipeWire::SelectSource(SourceId id) {
+   return true;
+ }
+ 
++// static
++std::unique_ptr<DesktopCapturer> BaseCapturerPipeWire::CreateRawCapturer(
++    const DesktopCaptureOptions& options) {
++  return std::make_unique<BaseCapturerPipeWire>(
++      BaseCapturerPipeWire::CaptureSourceType::kAny);
++}
++
+ }  // namespace webrtc
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h b/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
+index f28d7a558bc..75d20dbf1db 100644
+--- a/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
++++ b/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
+@@ -10,18 +10,23 @@
+ 
+ #ifndef MODULES_DESKTOP_CAPTURE_LINUX_BASE_CAPTURER_PIPEWIRE_H_
+ #define MODULES_DESKTOP_CAPTURE_LINUX_BASE_CAPTURER_PIPEWIRE_H_
+-
+ #include <gio/gio.h>
+ #define typeof __typeof__
+ #include <pipewire/pipewire.h>
+ #include <spa/param/video/format-utils.h>
++#if PW_CHECK_VERSION(0, 3, 0)
++#include <spa/utils/result.h>
++#endif
+ 
++#include "absl/types/optional.h"
+ #include "modules/desktop_capture/desktop_capture_options.h"
+ #include "modules/desktop_capture/desktop_capturer.h"
+ #include "rtc_base/constructor_magic.h"
++#include "rtc_base/synchronization/mutex.h"
+ 
+ namespace webrtc {
+ 
++#if !PW_CHECK_VERSION(0, 3, 0)
+ class PipeWireType {
+  public:
+   spa_type_media_type media_type;
+@@ -29,14 +34,25 @@ class PipeWireType {
+   spa_type_format_video format_video;
+   spa_type_video_format video_format;
+ };
++#endif
+ 
+ class BaseCapturerPipeWire : public DesktopCapturer {
+  public:
+-  enum CaptureSourceType { Screen = 1, Window };
++  // Values are set based on source type property in
++  // xdg-desktop-portal/screencast
++  // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml
++  enum class CaptureSourceType : uint32_t {
++    kScreen = 0b01,
++    kWindow = 0b10,
++    kAny = 0b11
++  };
+ 
+   explicit BaseCapturerPipeWire(CaptureSourceType source_type);
+   ~BaseCapturerPipeWire() override;
+ 
++  static std::unique_ptr<DesktopCapturer> CreateRawCapturer(
++      const DesktopCaptureOptions& options);
++
+   // DesktopCapturer interface.
+   void Start(Callback* delegate) override;
+   void CaptureFrame() override;
+@@ -45,6 +61,21 @@ class BaseCapturerPipeWire : public DesktopCapturer {
+ 
+  private:
+   // PipeWire types -->
++#if PW_CHECK_VERSION(0, 3, 0)
++  struct pw_context* pw_context_ = nullptr;
++  struct pw_core* pw_core_ = nullptr;
++  struct pw_stream* pw_stream_ = nullptr;
++  struct pw_thread_loop* pw_main_loop_ = nullptr;
++
++  spa_hook spa_core_listener_;
++  spa_hook spa_stream_listener_;
++
++  // event handlers
++  pw_core_events pw_core_events_ = {};
++  pw_stream_events pw_stream_events_ = {};
++
++  struct spa_video_info_raw spa_video_format_;
++#else
+   pw_core* pw_core_ = nullptr;
+   pw_type* pw_core_type_ = nullptr;
+   pw_stream* pw_stream_ = nullptr;
+@@ -60,11 +91,13 @@ class BaseCapturerPipeWire : public DesktopCapturer {
+   pw_remote_events pw_remote_events_ = {};
+ 
+   spa_video_info_raw* spa_video_format_ = nullptr;
++#endif
+ 
++  guint32 pw_stream_node_id_ = 0;
+   gint32 pw_fd_ = -1;
+ 
+   CaptureSourceType capture_source_type_ =
+-      BaseCapturerPipeWire::CaptureSourceType::Screen;
++      BaseCapturerPipeWire::CaptureSourceType::kScreen;
+ 
+   // <-- end of PipeWire types
+ 
+@@ -79,10 +112,12 @@ class BaseCapturerPipeWire : public DesktopCapturer {
+   guint sources_request_signal_id_ = 0;
+   guint start_request_signal_id_ = 0;
+ 
++  DesktopSize video_size_;
+   DesktopSize desktop_size_ = {};
+   DesktopCaptureOptions options_ = {};
+ 
+-  uint8_t* current_frame_ = nullptr;
++  webrtc::Mutex current_frame_lock_;
++  std::unique_ptr<uint8_t[]> current_frame_;
+   Callback* callback_ = nullptr;
+ 
+   bool portal_init_failed_ = false;
+@@ -91,21 +126,32 @@ class BaseCapturerPipeWire : public DesktopCapturer {
+   void InitPipeWire();
+   void InitPipeWireTypes();
+ 
+-  void CreateReceivingStream();
++  pw_stream* CreateReceivingStream();
+   void HandleBuffer(pw_buffer* buffer);
+ 
+   void ConvertRGBxToBGRx(uint8_t* frame, uint32_t size);
+ 
++#if PW_CHECK_VERSION(0, 3, 0)
++  static void OnCoreError(void* data,
++                          uint32_t id,
++                          int seq,
++                          int res,
++                          const char* message);
++  static void OnStreamParamChanged(void* data,
++                                   uint32_t id,
++                                   const struct spa_pod* format);
++#else
+   static void OnStateChanged(void* data,
+                              pw_remote_state old_state,
+                              pw_remote_state state,
+                              const char* error);
++  static void OnStreamFormatChanged(void* data, const struct spa_pod* format);
++#endif
+   static void OnStreamStateChanged(void* data,
+                                    pw_stream_state old_state,
+                                    pw_stream_state state,
+                                    const char* error_message);
+ 
+-  static void OnStreamFormatChanged(void* data, const struct spa_pod* format);
+   static void OnStreamProcess(void* data);
+   static void OnNewBuffer(void* data, uint32_t id);
+ 
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire.sigs b/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire.sigs
+deleted file mode 100644
+index 3e21e9dc07c..00000000000
+--- a/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire.sigs
++++ /dev/null
+@@ -1,44 +0,0 @@
+-// Copyright 2018 The WebRTC project authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style license that can be
+-// found in the LICENSE file.
+-
+-//------------------------------------------------
+-// Functions from PipeWire used in capturer code.
+-//------------------------------------------------
+-
+-// core.h
+-void pw_core_destroy(pw_core *core);
+-pw_type *pw_core_get_type(pw_core *core);
+-pw_core * pw_core_new(pw_loop *main_loop, pw_properties *props);
+-
+-// loop.h
+-void pw_loop_destroy(pw_loop *loop);
+-pw_loop * pw_loop_new(pw_properties *properties);
+-
+-// pipewire.h
+-void pw_init(int *argc, char **argv[]);
+-
+-// properties.h
+-pw_properties * pw_properties_new_string(const char *args);
+-
+-// remote.h
+-void pw_remote_add_listener(pw_remote *remote, spa_hook *listener, const pw_remote_events *events, void *data);
+-int pw_remote_connect_fd(pw_remote *remote, int fd);
+-void pw_remote_destroy(pw_remote *remote);
+-pw_remote * pw_remote_new(pw_core *core, pw_properties *properties, size_t user_data_size);
+-
+-// stream.h
+-void pw_stream_add_listener(pw_stream *stream, spa_hook *listener, const pw_stream_events *events, void *data);
+-int pw_stream_connect(pw_stream *stream, enum pw_direction direction, const char *port_path, enum pw_stream_flags flags, const spa_pod **params, uint32_t n_params);
+-pw_buffer *pw_stream_dequeue_buffer(pw_stream *stream);
+-void pw_stream_destroy(pw_stream *stream);
+-void pw_stream_finish_format(pw_stream *stream, int res, const spa_pod **params, uint32_t n_params);
+-pw_stream * pw_stream_new(pw_remote *remote, const char *name, pw_properties *props);
+-int pw_stream_queue_buffer(pw_stream *stream, pw_buffer *buffer);
+-int pw_stream_set_active(pw_stream *stream, bool active);
+-
+-// thread-loop.h
+-void pw_thread_loop_destroy(pw_thread_loop *loop);
+-pw_thread_loop * pw_thread_loop_new(pw_loop *loop, const char *name);
+-int pw_thread_loop_start(pw_thread_loop *loop);
+-void pw_thread_loop_stop(pw_thread_loop *loop);
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc b/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc
+deleted file mode 100644
+index fe672140cca..00000000000
+--- a/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc
++++ /dev/null
+@@ -1,29 +0,0 @@
+-/*
+- *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
+- *
+- *  Use of this source code is governed by a BSD-style license
+- *  that can be found in the LICENSE file in the root of the source
+- *  tree. An additional intellectual property rights grant can be found
+- *  in the file PATENTS.  All contributing project authors may
+- *  be found in the AUTHORS file in the root of the source tree.
+- */
+-
+-#include "modules/desktop_capture/linux/screen_capturer_pipewire.h"
+-
+-#include <memory>
+-
+-
+-namespace webrtc {
+-
+-ScreenCapturerPipeWire::ScreenCapturerPipeWire()
+-    : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Screen) {}
+-ScreenCapturerPipeWire::~ScreenCapturerPipeWire() {}
+-
+-// static
+-std::unique_ptr<DesktopCapturer>
+-ScreenCapturerPipeWire::CreateRawScreenCapturer(
+-    const DesktopCaptureOptions& options) {
+-  return std::make_unique<ScreenCapturerPipeWire>();
+-}
+-
+-}  // namespace webrtc
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.h b/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.h
+deleted file mode 100644
+index 66dcd680e06..00000000000
+--- a/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.h
++++ /dev/null
+@@ -1,33 +0,0 @@
+-/*
+- *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
+- *
+- *  Use of this source code is governed by a BSD-style license
+- *  that can be found in the LICENSE file in the root of the source
+- *  tree. An additional intellectual property rights grant can be found
+- *  in the file PATENTS.  All contributing project authors may
+- *  be found in the AUTHORS file in the root of the source tree.
+- */
+-
+-#ifndef MODULES_DESKTOP_CAPTURE_LINUX_SCREEN_CAPTURER_PIPEWIRE_H_
+-#define MODULES_DESKTOP_CAPTURE_LINUX_SCREEN_CAPTURER_PIPEWIRE_H_
+-
+-#include <memory>
+-
+-#include "modules/desktop_capture/linux/base_capturer_pipewire.h"
+-
+-namespace webrtc {
+-
+-class ScreenCapturerPipeWire : public BaseCapturerPipeWire {
+- public:
+-  ScreenCapturerPipeWire();
+-  ~ScreenCapturerPipeWire() override;
+-
+-  static std::unique_ptr<DesktopCapturer> CreateRawScreenCapturer(
+-      const DesktopCaptureOptions& options);
+-
+-  RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerPipeWire);
+-};
+-
+-}  // namespace webrtc
+-
+-#endif  // MODULES_DESKTOP_CAPTURE_LINUX_SCREEN_CAPTURER_PIPEWIRE_H_
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc b/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc
+deleted file mode 100644
+index b4559156dce..00000000000
+--- a/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc
++++ /dev/null
+@@ -1,29 +0,0 @@
+-/*
+- *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
+- *
+- *  Use of this source code is governed by a BSD-style license
+- *  that can be found in the LICENSE file in the root of the source
+- *  tree. An additional intellectual property rights grant can be found
+- *  in the file PATENTS.  All contributing project authors may
+- *  be found in the AUTHORS file in the root of the source tree.
+- */
+-
+-#include "modules/desktop_capture/linux/window_capturer_pipewire.h"
+-
+-#include <memory>
+-
+-
+-namespace webrtc {
+-
+-WindowCapturerPipeWire::WindowCapturerPipeWire()
+-    : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Window) {}
+-WindowCapturerPipeWire::~WindowCapturerPipeWire() {}
+-
+-// static
+-std::unique_ptr<DesktopCapturer>
+-WindowCapturerPipeWire::CreateRawWindowCapturer(
+-    const DesktopCaptureOptions& options) {
+-  return std::make_unique<WindowCapturerPipeWire>();
+-}
+-
+-}  // namespace webrtc
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.h b/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.h
+deleted file mode 100644
+index 7f184ef2999..00000000000
+--- a/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.h
++++ /dev/null
+@@ -1,33 +0,0 @@
+-/*
+- *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
+- *
+- *  Use of this source code is governed by a BSD-style license
+- *  that can be found in the LICENSE file in the root of the source
+- *  tree. An additional intellectual property rights grant can be found
+- *  in the file PATENTS.  All contributing project authors may
+- *  be found in the AUTHORS file in the root of the source tree.
+- */
+-
+-#ifndef MODULES_DESKTOP_CAPTURE_LINUX_WINDOW_CAPTURER_PIPEWIRE_H_
+-#define MODULES_DESKTOP_CAPTURE_LINUX_WINDOW_CAPTURER_PIPEWIRE_H_
+-
+-#include <memory>
+-
+-#include "modules/desktop_capture/linux/base_capturer_pipewire.h"
+-
+-namespace webrtc {
+-
+-class WindowCapturerPipeWire : public BaseCapturerPipeWire {
+- public:
+-  WindowCapturerPipeWire();
+-  ~WindowCapturerPipeWire() override;
+-
+-  static std::unique_ptr<DesktopCapturer> CreateRawWindowCapturer(
+-      const DesktopCaptureOptions& options);
+-
+-  RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerPipeWire);
+-};
+-
+-}  // namespace webrtc
+-
+-#endif  // MODULES_DESKTOP_CAPTURE_LINUX_WINDOW_CAPTURER_PIPEWIRE_H_
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_linux.cc b/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_linux.cc
+index 82dbae48137..ed48b7d6d59 100644
+--- a/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_linux.cc
++++ b/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_linux.cc
+@@ -14,7 +14,7 @@
+ #include "modules/desktop_capture/desktop_capturer.h"
+ 
+ #if defined(WEBRTC_USE_PIPEWIRE)
+-#include "modules/desktop_capture/linux/screen_capturer_pipewire.h"
++#include "modules/desktop_capture/linux/base_capturer_pipewire.h"
+ #endif  // defined(WEBRTC_USE_PIPEWIRE)
+ 
+ #if defined(WEBRTC_USE_X11)
+@@ -28,7 +28,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer(
+     const DesktopCaptureOptions& options) {
+ #if defined(WEBRTC_USE_PIPEWIRE)
+   if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
+-    return ScreenCapturerPipeWire::CreateRawScreenCapturer(options);
++    return BaseCapturerPipeWire::CreateRawCapturer(options);
+   }
+ #endif  // defined(WEBRTC_USE_PIPEWIRE)
+ 
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/window_capturer_linux.cc b/chromium/third_party/webrtc/modules/desktop_capture/window_capturer_linux.cc
+index 41dbf836b03..2b142ae3b92 100644
+--- a/chromium/third_party/webrtc/modules/desktop_capture/window_capturer_linux.cc
++++ b/chromium/third_party/webrtc/modules/desktop_capture/window_capturer_linux.cc
+@@ -14,7 +14,7 @@
+ #include "modules/desktop_capture/desktop_capturer.h"
+ 
+ #if defined(WEBRTC_USE_PIPEWIRE)
+-#include "modules/desktop_capture/linux/window_capturer_pipewire.h"
++#include "modules/desktop_capture/linux/base_capturer_pipewire.h"
+ #endif  // defined(WEBRTC_USE_PIPEWIRE)
+ 
+ #if defined(WEBRTC_USE_X11)
+@@ -28,7 +28,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer(
+     const DesktopCaptureOptions& options) {
+ #if defined(WEBRTC_USE_PIPEWIRE)
+   if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
+-    return WindowCapturerPipeWire::CreateRawWindowCapturer(options);
++    return BaseCapturerPipeWire::CreateRawCapturer(options);
+   }
+ #endif  // defined(WEBRTC_USE_PIPEWIRE)
+ 
+diff --git a/chromium/third_party/webrtc/webrtc.gni b/chromium/third_party/webrtc/webrtc.gni
+index ca8acdbf259..505c975cece 100644
+--- a/chromium/third_party/webrtc/webrtc.gni
++++ b/chromium/third_party/webrtc/webrtc.gni
+@@ -117,6 +117,10 @@ declare_args() {
+   # Set this to link PipeWire directly instead of using the dlopen.
+   rtc_link_pipewire = false
+ 
++  # Set this to use certain PipeWire version
++  # Currently we support PipeWire 0.2 (default) and PipeWire 0.3
++  rtc_pipewire_version = "0.3"
++
+   # Enable to use the Mozilla internal settings.
+   build_with_mozilla = false
+ 
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire02.sigs b/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire02.sigs
+new file mode 100644
+index 00000000000..5ac3d1d22b8
+--- /dev/null
++++ b/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire02.sigs
+@@ -0,0 +1,47 @@
++// Copyright 2018 The WebRTC project authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++//------------------------------------------------
++// Functions from PipeWire used in capturer code.
++//------------------------------------------------
++
++// core.h
++void pw_core_destroy(pw_core *core);
++pw_type *pw_core_get_type(pw_core *core);
++pw_core * pw_core_new(pw_loop *main_loop, pw_properties *props);
++
++// loop.h
++void pw_loop_destroy(pw_loop *loop);
++pw_loop * pw_loop_new(pw_properties *properties);
++
++// pipewire.h
++void pw_init(int *argc, char **argv[]);
++
++// properties.h
++pw_properties * pw_properties_new_string(const char *args);
++
++// remote.h
++void pw_remote_add_listener(pw_remote *remote, spa_hook *listener, const pw_remote_events *events, void *data);
++int pw_remote_connect_fd(pw_remote *remote, int fd);
++void pw_remote_destroy(pw_remote *remote);
++pw_remote * pw_remote_new(pw_core *core, pw_properties *properties, size_t user_data_size);
++enum pw_remote_state pw_remote_get_state(pw_remote *remote, const char **error);
++
++// stream.h
++void pw_stream_add_listener(pw_stream *stream, spa_hook *listener, const pw_stream_events *events, void *data);
++int pw_stream_connect(pw_stream *stream, enum pw_direction direction, const char *port_path, enum pw_stream_flags flags, const spa_pod **params, uint32_t n_params);
++pw_buffer *pw_stream_dequeue_buffer(pw_stream *stream);
++void pw_stream_destroy(pw_stream *stream);
++void pw_stream_finish_format(pw_stream *stream, int res, const spa_pod **params, uint32_t n_params);
++pw_stream * pw_stream_new(pw_remote *remote, const char *name, pw_properties *props);
++int pw_stream_queue_buffer(pw_stream *stream, pw_buffer *buffer);
++int pw_stream_set_active(pw_stream *stream, bool active);
++
++// thread-loop.h
++void pw_thread_loop_destroy(pw_thread_loop *loop);
++pw_thread_loop * pw_thread_loop_new(pw_loop *loop, const char *name);
++int pw_thread_loop_start(pw_thread_loop *loop);
++void pw_thread_loop_stop(pw_thread_loop *loop);
++void pw_thread_loop_lock(struct pw_thread_loop *loop);
++void pw_thread_loop_unlock(struct pw_thread_loop *loop);
+diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire03.sigs b/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire03.sigs
+new file mode 100644
+index 00000000000..78d241f40c6
+--- /dev/null
++++ b/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire03.sigs
+@@ -0,0 +1,46 @@
++// Copyright 2018 The WebRTC project authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++//------------------------------------------------
++// Functions from PipeWire used in capturer code.
++//------------------------------------------------
++
++// core.h
++int pw_core_disconnect(pw_core *core);
++
++// loop.h
++void pw_loop_destroy(pw_loop *loop);
++pw_loop * pw_loop_new(const spa_dict *props);
++
++
++// pipewire.h
++void pw_init(int *argc, char **argv[]);
++
++// properties.h
++pw_properties * pw_properties_new_string(const char *args);
++
++// stream.h
++void pw_stream_add_listener(pw_stream *stream, spa_hook *listener, const pw_stream_events *events, void *data);
++int pw_stream_connect(pw_stream *stream, enum pw_direction direction, uint32_t target_id, enum pw_stream_flags flags, const spa_pod **params, uint32_t n_params);
++pw_buffer *pw_stream_dequeue_buffer(pw_stream *stream);
++void pw_stream_destroy(pw_stream *stream);
++pw_stream * pw_stream_new(pw_core *core, const char *name, pw_properties *props);
++int pw_stream_queue_buffer(pw_stream *stream, pw_buffer *buffer);
++int pw_stream_set_active(pw_stream *stream, bool active);
++int pw_stream_update_params(pw_stream *stream, const spa_pod **params, uint32_t n_params);
++
++// thread-loop.h
++void pw_thread_loop_destroy(pw_thread_loop *loop);
++pw_thread_loop * pw_thread_loop_new(const char *name, const spa_dict *props);
++int pw_thread_loop_start(pw_thread_loop *loop);
++void pw_thread_loop_stop(pw_thread_loop *loop);
++void pw_thread_loop_lock(pw_thread_loop *loop);
++void pw_thread_loop_unlock(pw_thread_loop *loop);
++pw_loop * pw_thread_loop_get_loop(pw_thread_loop *loop);
++
++
++// context.h
++void pw_context_destroy(pw_context *context);
++pw_context *pw_context_new(pw_loop *main_loop, pw_properties *props, size_t user_data_size);
++pw_core * pw_context_connect(pw_context *context, pw_properties *properties, size_t user_data_size);
-- 
cgit v0.12

