diff options
Diffstat (limited to 'modules/text_server_adv/text_server_adv.cpp')
-rw-r--r-- | modules/text_server_adv/text_server_adv.cpp | 400 |
1 files changed, 233 insertions, 167 deletions
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 8987a491cb..bcc7bff909 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -1113,14 +1113,14 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma case FT_PIXEL_MODE_LCD: { int ofs_color = i * bitmap.pitch + (j * 3); if (p_bgra) { - wr[ofs + 0] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 0] = bitmap.buffer[ofs_color + 2]; wr[ofs + 1] = bitmap.buffer[ofs_color + 1]; - wr[ofs + 2] = bitmap.buffer[ofs_color + 2]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 0]; wr[ofs + 3] = 255; } else { - wr[ofs + 0] = bitmap.buffer[ofs_color + 2]; + wr[ofs + 0] = bitmap.buffer[ofs_color + 0]; wr[ofs + 1] = bitmap.buffer[ofs_color + 1]; - wr[ofs + 2] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 2]; wr[ofs + 3] = 255; } } break; @@ -3504,6 +3504,9 @@ void TextServerAdvanced::_font_render_glyph(const RID &p_font_rid, const Vector2 } void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { + if (p_index == 0) { + return; // Non visual character, skip. + } FontAdvanced *fd = _get_font_data(p_font_rid); ERR_FAIL_NULL(fd); @@ -3541,6 +3544,9 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca const FontGlyph &gl = fd->cache[size]->glyph_map[index]; if (gl.found) { + if (gl.uv_rect.size.x <= 2 || gl.uv_rect.size.y <= 2) { + return; // Nothing to draw. + } ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); if (gl.texture_idx != -1) { @@ -3608,6 +3614,9 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca } void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { + if (p_index == 0) { + return; // Non visual character, skip. + } FontAdvanced *fd = _get_font_data(p_font_rid); ERR_FAIL_NULL(fd); @@ -3645,6 +3654,9 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R const FontGlyph &gl = fd->cache[size]->glyph_map[index]; if (gl.found) { + if (gl.uv_rect.size.x <= 2 || gl.uv_rect.size.y <= 2) { + return; // Nothing to draw. + } ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size()); if (gl.texture_idx != -1) { @@ -4048,6 +4060,20 @@ String TextServerAdvanced::_shaped_text_get_custom_punctuation(const RID &p_shap return sd->custom_punct; } +void TextServerAdvanced::_shaped_text_set_custom_ellipsis(const RID &p_shaped, int64_t p_char) { + _THREAD_SAFE_METHOD_ + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_NULL(sd); + sd->el_char = p_char; +} + +int64_t TextServerAdvanced::_shaped_text_get_custom_ellipsis(const RID &p_shaped) const { + _THREAD_SAFE_METHOD_ + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_NULL_V(sd, 0); + return sd->el_char; +} + void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_NULL(sd); @@ -4312,6 +4338,8 @@ bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const V sd->width += gl.advance * gl.repeat; } } + sd->sort_valid = false; + sd->glyphs_logical.clear(); _realign(sd); } return true; @@ -4798,6 +4826,166 @@ double TextServerAdvanced::_shaped_text_tab_align(const RID &p_shaped, const Pac return 0.0; } +RID TextServerAdvanced::_find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text) { + RID f; + // Try system fallback. + String font_name = _font_get_name(p_fdef); + BitField<FontStyle> font_style = _font_get_style(p_fdef); + int font_weight = _font_get_weight(p_fdef); + int font_stretch = _font_get_stretch(p_fdef); + Dictionary dvar = _font_get_variation_coordinates(p_fdef); + static int64_t wgth_tag = _name_to_tag("weight"); + static int64_t wdth_tag = _name_to_tag("width"); + static int64_t ital_tag = _name_to_tag("italic"); + if (dvar.has(wgth_tag)) { + font_weight = dvar[wgth_tag].operator int(); + } + if (dvar.has(wdth_tag)) { + font_stretch = dvar[wdth_tag].operator int(); + } + if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) { + font_style.set_flag(TextServer::FONT_ITALIC); + } + + String locale = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; + PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, p_text, locale, p_script_code, font_weight, font_stretch, font_style & TextServer::FONT_ITALIC); +#ifdef GDEXTENSION + for (int fb = 0; fb < fallback_font_name.size(); fb++) { + const String &E = fallback_font_name[fb]; +#else + for (const String &E : fallback_font_name) { +#endif + SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this); + if (system_fonts.has(key)) { + const SystemFontCache &sysf_cache = system_fonts[key]; + int best_score = 0; + int best_match = -1; + for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) { + const SystemFontCacheRec &F = sysf_cache.var[face_idx]; + if (unlikely(!_font_has_char(F.rid, p_text[0]))) { + continue; + } + BitField<FontStyle> style = _font_get_style(F.rid); + int weight = _font_get_weight(F.rid); + int stretch = _font_get_stretch(F.rid); + int score = (20 - Math::abs(weight - font_weight) / 50); + score += (20 - Math::abs(stretch - font_stretch) / 10); + if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { + score += 30; + } + if (score >= best_score) { + best_score = score; + best_match = face_idx; + } + if (best_score == 70) { + break; + } + } + if (best_match != -1) { + f = sysf_cache.var[best_match].rid; + } + } + if (!f.is_valid()) { + if (system_fonts.has(key)) { + const SystemFontCache &sysf_cache = system_fonts[key]; + if (sysf_cache.max_var == sysf_cache.var.size()) { + // All subfonts already tested, skip. + continue; + } + } + + if (!system_font_data.has(E)) { + system_font_data[E] = FileAccess::get_file_as_bytes(E); + } + + const PackedByteArray &font_data = system_font_data[E]; + + SystemFontCacheRec sysf; + sysf.rid = _create_font(); + _font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size()); + + Dictionary var = dvar; + // Select matching style from collection. + int best_score = 0; + int best_match = -1; + for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) { + _font_set_face_index(sysf.rid, face_idx); + if (unlikely(!_font_has_char(sysf.rid, p_text[0]))) { + continue; + } + BitField<FontStyle> style = _font_get_style(sysf.rid); + int weight = _font_get_weight(sysf.rid); + int stretch = _font_get_stretch(sysf.rid); + int score = (20 - Math::abs(weight - font_weight) / 50); + score += (20 - Math::abs(stretch - font_stretch) / 10); + if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { + score += 30; + } + if (score >= best_score) { + best_score = score; + best_match = face_idx; + } + if (best_score == 70) { + break; + } + } + if (best_match == -1) { + _free_rid(sysf.rid); + continue; + } else { + _font_set_face_index(sysf.rid, best_match); + } + sysf.index = best_match; + + // If it's a variable font, apply weight, stretch and italic coordinates to match requested style. + if (best_score != 70) { + Dictionary ftr = _font_supported_variation_list(sysf.rid); + if (ftr.has(wdth_tag)) { + var[wdth_tag] = font_stretch; + _font_set_stretch(sysf.rid, font_stretch); + } + if (ftr.has(wgth_tag)) { + var[wgth_tag] = font_weight; + _font_set_weight(sysf.rid, font_weight); + } + if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) { + var[ital_tag] = 1; + _font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC); + } + } + + _font_set_antialiasing(sysf.rid, key.antialiasing); + _font_set_generate_mipmaps(sysf.rid, key.mipmaps); + _font_set_multichannel_signed_distance_field(sysf.rid, key.msdf); + _font_set_msdf_pixel_range(sysf.rid, key.msdf_range); + _font_set_msdf_size(sysf.rid, key.msdf_source_size); + _font_set_fixed_size(sysf.rid, key.fixed_size); + _font_set_force_autohinter(sysf.rid, key.force_autohinter); + _font_set_hinting(sysf.rid, key.hinting); + _font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning); + _font_set_variation_coordinates(sysf.rid, var); + _font_set_oversampling(sysf.rid, key.oversampling); + _font_set_embolden(sysf.rid, key.embolden); + _font_set_transform(sysf.rid, key.transform); + _font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]); + _font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]); + _font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]); + _font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]); + + if (system_fonts.has(key)) { + system_fonts[key].var.push_back(sysf); + } else { + SystemFontCache &sysf_cache = system_fonts[key]; + sysf_cache.max_var = _font_get_face_count(sysf.rid); + sysf_cache.var.push_back(sysf); + } + f = sysf.rid; + } + break; + } + return f; +} + void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line); ERR_FAIL_NULL_MSG(sd, "ShapedTextDataAdvanced invalid."); @@ -4840,20 +5028,52 @@ void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ int sd_size = sd->glyphs.size(); int last_gl_font_size = sd_glyphs[sd_size - 1].font_size; + bool found_el_char = false; // Find usable fonts, if fonts from the last glyph do not have required chars. RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!_font_has_char(dot_gl_font_rid, '.')) { + if (!_font_has_char(dot_gl_font_rid, sd->el_char)) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { - if (_font_has_char(fonts[i], '.')) { + if (_font_has_char(fonts[i], sd->el_char)) { dot_gl_font_rid = fonts[i]; + found_el_char = true; break; } } + if (!found_el_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) { + const char32_t u32str[] = { sd->el_char, 0 }; + RID rid = _find_sys_font_for_text(fonts[0], String(), spans[spans.size() - 1].language, u32str); + if (rid.is_valid()) { + dot_gl_font_rid = rid; + found_el_char = true; + } + } + } else { + found_el_char = true; + } + if (!found_el_char) { + bool found_dot_char = false; + dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + if (!_font_has_char(dot_gl_font_rid, '.')) { + const Array &fonts = spans[spans.size() - 1].fonts; + for (int i = 0; i < fonts.size(); i++) { + if (_font_has_char(fonts[i], '.')) { + dot_gl_font_rid = fonts[i]; + found_dot_char = true; + break; + } + } + if (!found_dot_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) { + RID rid = _find_sys_font_for_text(fonts[0], String(), spans[spans.size() - 1].language, "."); + if (rid.is_valid()) { + dot_gl_font_rid = rid; + } + } + } } RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!_font_has_char(whitespace_gl_font_rid, '.')) { + if (!_font_has_char(whitespace_gl_font_rid, ' ')) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { if (_font_has_char(fonts[i], ' ')) { @@ -4863,14 +5083,14 @@ void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ } } - int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.', 0) : -10; + int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, (found_el_char ? sd->el_char : '.'), 0) : -1; Vector2 dot_adv = dot_gl_font_rid.is_valid() ? _font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); - int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -10; + int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -1; Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); int ellipsis_width = 0; if (add_ellipsis && whitespace_gl_font_rid.is_valid()) { - ellipsis_width = 3 * dot_adv.x + sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(dot_gl_font_rid, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); + ellipsis_width = (found_el_char ? 1 : 3) * dot_adv.x + sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(dot_gl_font_rid, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); } int ell_min_characters = 6; @@ -4949,7 +5169,7 @@ void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_ if (dot_gl_idx != 0) { Glyph gl; gl.count = 1; - gl.repeat = 3; + gl.repeat = (found_el_char ? 1 : 3); gl.advance = dot_adv.x; gl.index = dot_gl_idx; gl.font_rid = dot_gl_font_rid; @@ -5578,166 +5798,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star break; } } - String text = p_sd->text.substr(p_start, next - p_start); - - String font_name = _font_get_name(fdef); - BitField<FontStyle> font_style = _font_get_style(fdef); - int font_weight = _font_get_weight(fdef); - int font_stretch = _font_get_stretch(fdef); - Dictionary dvar = _font_get_variation_coordinates(fdef); - static int64_t wgth_tag = _name_to_tag("weight"); - static int64_t wdth_tag = _name_to_tag("width"); - static int64_t ital_tag = _name_to_tag("italic"); - if (dvar.has(wgth_tag)) { - font_weight = dvar[wgth_tag].operator int(); - } - if (dvar.has(wdth_tag)) { - font_stretch = dvar[wdth_tag].operator int(); - } - if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) { - font_style.set_flag(TextServer::FONT_ITALIC); - } - char scr_buffer[5] = { 0, 0, 0, 0, 0 }; hb_tag_to_string(hb_script_to_iso15924_tag(p_script), scr_buffer); String script_code = String(scr_buffer); - String locale = (p_sd->spans[p_span].language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_sd->spans[p_span].language; - PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, text, locale, script_code, font_weight, font_stretch, font_style & TextServer::FONT_ITALIC); -#ifdef GDEXTENSION - for (int fb = 0; fb < fallback_font_name.size(); fb++) { - const String &E = fallback_font_name[fb]; -#else - for (const String &E : fallback_font_name) { -#endif - SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, fdef, this); - if (system_fonts.has(key)) { - const SystemFontCache &sysf_cache = system_fonts[key]; - int best_score = 0; - int best_match = -1; - for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) { - const SystemFontCacheRec &F = sysf_cache.var[face_idx]; - if (unlikely(!_font_has_char(F.rid, text[0]))) { - continue; - } - BitField<FontStyle> style = _font_get_style(F.rid); - int weight = _font_get_weight(F.rid); - int stretch = _font_get_stretch(F.rid); - int score = (20 - Math::abs(weight - font_weight) / 50); - score += (20 - Math::abs(stretch - font_stretch) / 10); - if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { - score += 30; - } - if (score >= best_score) { - best_score = score; - best_match = face_idx; - } - if (best_score == 70) { - break; - } - } - if (best_match != -1) { - f = sysf_cache.var[best_match].rid; - } - } - if (!f.is_valid()) { - if (system_fonts.has(key)) { - const SystemFontCache &sysf_cache = system_fonts[key]; - if (sysf_cache.max_var == sysf_cache.var.size()) { - // All subfonts already tested, skip. - continue; - } - } - - if (!system_font_data.has(E)) { - system_font_data[E] = FileAccess::get_file_as_bytes(E); - } - - const PackedByteArray &font_data = system_font_data[E]; - - SystemFontCacheRec sysf; - sysf.rid = _create_font(); - _font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size()); - - Dictionary var = dvar; - // Select matching style from collection. - int best_score = 0; - int best_match = -1; - for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) { - _font_set_face_index(sysf.rid, face_idx); - if (unlikely(!_font_has_char(sysf.rid, text[0]))) { - continue; - } - BitField<FontStyle> style = _font_get_style(sysf.rid); - int weight = _font_get_weight(sysf.rid); - int stretch = _font_get_stretch(sysf.rid); - int score = (20 - Math::abs(weight - font_weight) / 50); - score += (20 - Math::abs(stretch - font_stretch) / 10); - if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { - score += 30; - } - if (score >= best_score) { - best_score = score; - best_match = face_idx; - } - if (best_score == 70) { - break; - } - } - if (best_match == -1) { - _free_rid(sysf.rid); - continue; - } else { - _font_set_face_index(sysf.rid, best_match); - } - sysf.index = best_match; - - // If it's a variable font, apply weight, stretch and italic coordinates to match requested style. - if (best_score != 70) { - Dictionary ftr = _font_supported_variation_list(sysf.rid); - if (ftr.has(wdth_tag)) { - var[wdth_tag] = font_stretch; - _font_set_stretch(sysf.rid, font_stretch); - } - if (ftr.has(wgth_tag)) { - var[wgth_tag] = font_weight; - _font_set_weight(sysf.rid, font_weight); - } - if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) { - var[ital_tag] = 1; - _font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC); - } - } - - _font_set_antialiasing(sysf.rid, key.antialiasing); - _font_set_generate_mipmaps(sysf.rid, key.mipmaps); - _font_set_multichannel_signed_distance_field(sysf.rid, key.msdf); - _font_set_msdf_pixel_range(sysf.rid, key.msdf_range); - _font_set_msdf_size(sysf.rid, key.msdf_source_size); - _font_set_fixed_size(sysf.rid, key.fixed_size); - _font_set_force_autohinter(sysf.rid, key.force_autohinter); - _font_set_hinting(sysf.rid, key.hinting); - _font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning); - _font_set_variation_coordinates(sysf.rid, var); - _font_set_oversampling(sysf.rid, key.oversampling); - _font_set_embolden(sysf.rid, key.embolden); - _font_set_transform(sysf.rid, key.transform); - _font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]); - _font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]); - _font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]); - _font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]); - - if (system_fonts.has(key)) { - system_fonts[key].var.push_back(sysf); - } else { - SystemFontCache &sysf_cache = system_fonts[key]; - sysf_cache.max_var = _font_get_face_count(sysf.rid); - sysf_cache.var.push_back(sysf); - } - f = sysf.rid; - } - break; - } + String text = p_sd->text.substr(p_start, next - p_start); + f = _find_sys_font_for_text(fdef, script_code, p_sd->spans[p_span].language, text); } } |