mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 07:53:26 +00:00
[TextServer] Shape emojis as separate runs.
This commit is contained in:
parent
825ef2387f
commit
ddde1c07a6
4 changed files with 44 additions and 9 deletions
|
@ -32,10 +32,20 @@
|
|||
|
||||
// This implementation is derived from ICU: icu4c/source/extra/scrptrun/scrptrun.cpp
|
||||
|
||||
bool ScriptIterator::same_script(int32_t p_script_one, int32_t p_script_two) {
|
||||
inline bool ScriptIterator::same_script(int32_t p_script_one, int32_t p_script_two) {
|
||||
return p_script_one <= USCRIPT_INHERITED || p_script_two <= USCRIPT_INHERITED || p_script_one == p_script_two;
|
||||
}
|
||||
|
||||
inline bool ScriptIterator::is_emoji(UChar32 p_c, UChar32 p_next) {
|
||||
if (p_next == 0xFE0E) { // Variation Selector-15
|
||||
return false;
|
||||
} else if (p_next == 0xFE0F) { // Variation Selector-16
|
||||
return true;
|
||||
} else {
|
||||
return u_hasBinaryProperty(p_c, UCHAR_EMOJI) || u_hasBinaryProperty(p_c, UCHAR_EMOJI_PRESENTATION) || u_hasBinaryProperty(p_c, UCHAR_EMOJI_MODIFIER) || u_hasBinaryProperty(p_c, UCHAR_REGIONAL_INDICATOR) || u_hasBinaryProperty(p_c, UCHAR_EXTENDED_PICTOGRAPHIC);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length) {
|
||||
struct ParenStackEntry {
|
||||
int pair_index;
|
||||
|
@ -65,11 +75,16 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
|
|||
script_code = USCRIPT_COMMON;
|
||||
for (script_start = script_end; script_end < p_length; script_end++) {
|
||||
UChar32 ch = str[script_end];
|
||||
UChar32 n = (script_end + 1 < p_length) ? str[script_end + 1] : 0;
|
||||
UScriptCode sc = uscript_getScript(ch, &err);
|
||||
if (U_FAILURE(err)) {
|
||||
memfree(paren_stack);
|
||||
ERR_FAIL_MSG(u_errorName(err));
|
||||
}
|
||||
if (is_emoji(ch, n)) {
|
||||
sc = USCRIPT_SYMBOLS_EMOJI;
|
||||
}
|
||||
|
||||
if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) != U_BPT_NONE) {
|
||||
if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_OPEN) {
|
||||
// If it's an open character, push it onto the stack.
|
||||
|
@ -96,7 +111,12 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
|
|||
}
|
||||
}
|
||||
|
||||
if (same_script(script_code, sc)) {
|
||||
if (script_code == USCRIPT_SYMBOLS_EMOJI && script_code != sc) {
|
||||
UCharCategory cat = (UCharCategory)u_charType(ch);
|
||||
if ((cat >= U_SPACE_SEPARATOR && cat <= U_CONTROL_CHAR) || (cat >= U_DASH_PUNCTUATION && cat <= U_OTHER_PUNCTUATION) || (cat >= U_INITIAL_PUNCTUATION && cat <= U_FINAL_PUNCTUATION)) {
|
||||
break;
|
||||
}
|
||||
} else if (same_script(script_code, sc)) {
|
||||
if (script_code <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) {
|
||||
script_code = sc;
|
||||
// Now that we have a final script code, fix any open characters we pushed before we knew the script code.
|
||||
|
|
|
@ -68,7 +68,8 @@ public:
|
|||
Vector<ScriptRange> script_ranges;
|
||||
|
||||
private:
|
||||
static bool same_script(int32_t p_script_one, int32_t p_script_two);
|
||||
inline static bool same_script(int32_t p_script_one, int32_t p_script_two);
|
||||
inline static bool is_emoji(UChar32 p_c, UChar32 p_next);
|
||||
|
||||
public:
|
||||
ScriptIterator(const String &p_string, int p_start, int p_length);
|
||||
|
|
|
@ -2006,7 +2006,7 @@ _FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontAdvanced *p_font_d
|
|||
p_font_data->supported_scripts.clear();
|
||||
}
|
||||
|
||||
hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_t p_size) const {
|
||||
hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_t p_size, bool &r_is_color) const {
|
||||
FontAdvanced *fd = _get_font_data(p_font_rid);
|
||||
ERR_FAIL_NULL_V(fd, nullptr);
|
||||
|
||||
|
@ -2015,6 +2015,11 @@ hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_
|
|||
|
||||
FontForSizeAdvanced *ffsd = nullptr;
|
||||
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), nullptr);
|
||||
#ifdef MODULE_FREETYPE_ENABLED
|
||||
r_is_color = FT_HAS_COLOR(ffsd->face);
|
||||
#else
|
||||
r_is_color = false;
|
||||
#endif
|
||||
|
||||
return ffsd->hb_handle;
|
||||
}
|
||||
|
@ -6527,7 +6532,8 @@ bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shap
|
|||
}
|
||||
|
||||
Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size) {
|
||||
hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size);
|
||||
bool color = false;
|
||||
hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size, color);
|
||||
double scale = _font_get_scale(p_font, p_font_size);
|
||||
bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_AUTO && p_font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
|
||||
ERR_FAIL_NULL_V(hb_font, Glyph());
|
||||
|
@ -6535,7 +6541,7 @@ Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char
|
|||
hb_buffer_clear_contents(p_sd->hb_buffer);
|
||||
hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
|
||||
hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_DEFAULT));
|
||||
hb_buffer_set_script(p_sd->hb_buffer, p_script);
|
||||
hb_buffer_set_script(p_sd->hb_buffer, (p_script == HB_TAG('Z', 's', 'y', 'e')) ? HB_SCRIPT_COMMON : p_script);
|
||||
hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)&p_char, 1, 0, 1);
|
||||
|
||||
hb_shape(hb_font, p_sd->hb_buffer, nullptr, 0);
|
||||
|
@ -6740,9 +6746,17 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
|
|||
FontAdvanced *fd = _get_font_data(f);
|
||||
ERR_FAIL_NULL(fd);
|
||||
MutexLock lock(fd->mutex);
|
||||
bool color = false;
|
||||
|
||||
Vector2i fss = _get_size(fd, fs);
|
||||
hb_font_t *hb_font = _font_get_hb_handle(f, fs);
|
||||
hb_font_t *hb_font = _font_get_hb_handle(f, fs, color);
|
||||
|
||||
if (p_script == HB_TAG('Z', 's', 'y', 'e') && !color) {
|
||||
// Color emoji is requested, skip non-color font.
|
||||
_shape_run(p_sd, p_start, p_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end, f);
|
||||
return;
|
||||
}
|
||||
|
||||
double scale = _font_get_scale(f, fs);
|
||||
double sp_sp = p_sd->extra_spacing[SPACING_SPACE] + _font_get_spacing(f, SPACING_SPACE);
|
||||
double sp_gl = p_sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(f, SPACING_GLYPH);
|
||||
|
@ -6763,7 +6777,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
|
|||
flags |= HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
|
||||
#endif
|
||||
hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)flags);
|
||||
hb_buffer_set_script(p_sd->hb_buffer, p_script);
|
||||
hb_buffer_set_script(p_sd->hb_buffer, (p_script == HB_TAG('Z', 's', 'y', 'e')) ? HB_SCRIPT_COMMON : p_script);
|
||||
|
||||
if (p_sd->spans[p_span].language.is_empty()) {
|
||||
hb_language_t lang = hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1);
|
||||
|
|
|
@ -726,7 +726,7 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
static void _bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontForSizeAdvanced *p_face, bool p_unref);
|
||||
static hb_font_t *_bmp_font_create(TextServerAdvanced::FontForSizeAdvanced *p_face, hb_destroy_func_t p_destroy);
|
||||
|
||||
hb_font_t *_font_get_hb_handle(const RID &p_font, int64_t p_font_size) const;
|
||||
hb_font_t *_font_get_hb_handle(const RID &p_font, int64_t p_font_size, bool &r_is_color) const;
|
||||
|
||||
struct GlyphCompare { // For line breaking reordering.
|
||||
_FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue