c++unicodefreetypefontconfigharfbuzz

Is it possible to get unicode scripts supported by font?


I have set of libraries: fontconfig, freetype, harfbuzz. Is it possible to get scripts list supported by the font?

The task is to create a map of fonts for different unicode scripts.

HarfBuzz, for example, has enum that contains scripts. But I don't understand, is it possible to extract this info from hb_font_t or hb_face_t.

Or maybe it's possible to get this info from fontconfig or freetype?


Solution

  • It's possible, but is't very comfortable. I have found this solution:

    #include <hb.h>
    #include <magic-deps.h>
    
    struct TInstalledFont {
        std::string FilePath{};
        int FaceIndex{};
    
        std::shared_ptr<hb_face_t> HbFontFace{nullptr};
        std::unordered_set<char32_t> Unicodes{};
        std::unordered_set<int> HbScripts{};
    };
    
    const auto hbUniFuncs = hb_unicode_funcs_get_default();
    
    for (TInstalledFont& font : Fonts) {
      auto blob = hb_blob_create_from_file(font.FilePath.c_str());
      if (!blob) {
        throw std::runtime_error("Failed to load font");
      }
      DEFER(&blob) {
        hb_blob_destroy(blob);
      };
    
      const auto face = hb_face_create(blob, font.FaceIndex);
      if (!face) {
        throw std::runtime_error("Failed to load face");
      }
      hb_face_make_immutable(face);
    
      font.HbFontFace = std::shared_ptr<hb_face_t>(face, hb_face_destroy);
    
      auto unicodes = hb_set_create();
      DEFER(&unicodes) {
        hb_set_destroy(unicodes);
      };
      hb_face_collect_unicodes(face, unicodes);
    
      hb_codepoint_t val{};
      while (hb_set_next(unicodes, &val)) {
        font.Unicodes.insert(val);
    
        const hb_script_t tagScript = hb_unicode_script(hbUniFuncs, val);
        // int because hb_script_t doesn't support hashing
        font.HbScripts.insert(static_cast<int>(tagScript));
      }
    }