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