Mercurial > jwe > octave
changeset 29683:7511182e5e9b
Allow for automatic font substitution in graphics text rendering
* ft-text-renderer.cc (ft_manager::get_font) New optionnal argument to look
for a specific character code point.
(ft_manager::get_font): Dito. If code point is provided add it in the search
patern before subtitution.
(ft_text_renderer::process_character): Try to draw with a fallback font
when failing to load a specific code point in the orignal font.
* uisetfont.m: Disable new warning Octave:substituted-glyph.
author | Pantxo Diribarne <pantxo.diribarne@gmail.com> |
---|---|
date | Sun, 16 May 2021 13:17:20 +0200 |
parents | 08104b0629d5 |
children | 7ad7991e946a |
files | libinterp/corefcn/ft-text-renderer.cc scripts/gui/uisetfont.m |
diffstat | 2 files changed, 74 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/ft-text-renderer.cc Sun May 16 09:44:35 2021 +0200 +++ b/libinterp/corefcn/ft-text-renderer.cc Sun May 16 13:17:20 2021 +0200 @@ -161,10 +161,11 @@ static void cleanup_instance (void) { delete instance; instance = nullptr; } static FT_Face get_font (const std::string& name, const std::string& weight, - const std::string& angle, double size) + const std::string& angle, double size, + FT_ULong c = 0) { return (instance_ok () - ? instance->do_get_font (name, weight, angle, size) + ? instance->do_get_font (name, weight, angle, size, c) : nullptr); } @@ -278,7 +279,8 @@ } FT_Face do_get_font (const std::string& name, const std::string& weight, - const std::string& angle, double size) + const std::string& angle, double size, + FT_ULong search_code_point) { FT_Face retval = nullptr; @@ -286,7 +288,8 @@ // Look first into the font cache, then use fontconfig. If the font // is present in the cache, simply add a reference and return it. - ft_key key (name + ':' + weight + ':' + angle, size); + ft_key key (name + ':' + weight + ':' + angle + ':' + + std::to_string (search_code_point), size); ft_cache::const_iterator it = cache.find (key); if (it != cache.end ()) @@ -328,7 +331,7 @@ } #if defined (HAVE_FONTCONFIG) - if (name != "*" && fontconfig_initialized) + if ((search_code_point != 0 || name != "*") && fontconfig_initialized) { int fc_weight, fc_angle; @@ -354,12 +357,21 @@ FcPatternAddInteger (pat, FC_SLANT, fc_angle); FcPatternAddDouble (pat, FC_PIXEL_SIZE, size); + if (search_code_point > 0) + { + FcCharSet *minimal_charset = FcCharSetCreate (); + FcCharSetAddChar (minimal_charset, + static_cast<FcChar32> (search_code_point)); + FcPatternAddCharSet (pat, FC_CHARSET, minimal_charset); + } + if (FcConfigSubstitute (nullptr, pat, FcMatchPattern)) { FcResult res; FcPattern *match; FcDefaultSubstitute (pat); + match = FcFontMatch (nullptr, pat, &res); // FIXME: originally, this test also required that @@ -389,6 +401,7 @@ else { std::string ascii_file = sys::get_ASCII_filename (file); + if (FT_New_Face (library, ascii_file.c_str (), 0, &retval)) ::warning ("ft_manager: unable to load font: %s", file.c_str ()); #if defined (HAVE_FT_REFERENCE_FACE) @@ -827,8 +840,63 @@ && (! glyph_index || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))) { +#if defined (HAVE_FONTCONFIG) + // Try to substitue font + FT_Face sub_face = ft_manager::get_font (font.get_name (), + font.get_weight (), + font.get_angle (), + font.get_size (), + code); + + if (sub_face) + { + FT_Set_Char_Size (sub_face, 0, font.get_size ()*64, 0, 0); + + glyph_index = FT_Get_Char_Index (sub_face, code); + + if (glyph_index + && (FT_Load_Glyph (sub_face, glyph_index, FT_LOAD_DEFAULT) + == 0)) + { + static std::string sub_name; + + if (sub_name.empty () + || sub_name != std::string (sub_face->family_name)) + { + sub_name = sub_face->family_name; + warning_with_id ("Octave:substituted-glyph", + "text_renderer: substituting font to '%s' for some characters", + sub_face->family_name); + } + + // FIXME: With this approach the substituted font is + // not stored in the str_list and thus won't appear in + // svg output. + ft_font saved_font = font; + + font = ft_font (font.get_name (), font.get_weight (), + font.get_angle (), font.get_size (), + sub_face); + + process_character (code, previous); + + font = saved_font; + } + else + { + glyph_index = 0; + warn_missing_glyph (code); + } + } + else + { + glyph_index = 0; + warn_missing_glyph (code); + } +#else glyph_index = 0; warn_missing_glyph (code); +#endif } else if ((code == '\n') || (code == '\t')) {
--- a/scripts/gui/uisetfont.m Sun May 16 09:44:35 2021 +0200 +++ b/scripts/gui/uisetfont.m Sun May 16 13:17:20 2021 +0200 @@ -141,6 +141,7 @@ ## Run the dialog warning ("off", "Octave:missing-glyph", "local"); + warning ("off", "Octave:substituted-glyph", "local"); hf = run_fontdialog (sysfonts, h, fontstruct, ttl, str); ## Now wait for a button to be pressed or the figure to be closed