#include #include #include #include #include #include #include #include "fonts.h" class FcResultException : public std::exception { public: FcResultException(FcResult result) : _result(result) {} const char* what() const noexcept { switch (this->_result) { case FcResultMatch: return "FcResultException: Object exists with the specified ID"; case FcResultNoMatch: return "FcResultException: Object doesn't exist at all"; case FcResultTypeMismatch: return "FcResultException: Object exists, but the type doesn't match"; case FcResultNoId: return "FcResultException: Object exists, but has fewer values than specified"; case FcResultOutOfMemory: return "FcResultException: malloc failed"; } return "FcResultException: Unknown result"; } private: FcResult _result; }; static std::string get_filename(FcPattern* pattern, const char* family) { std::string filename; FcResult result; FcValue font_value; FcValue family_value = { .type = FcTypeString, .u = { .s = reinterpret_cast(family) } }; if (FcPatternAdd(pattern, FC_FAMILY, family_value, FcFalse) != FcTrue) { throw std::runtime_error(std::string("FcPatternAdd() for ") + family + " returned FcFalse"); } FcConfigSubstitute(nullptr, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcPattern* font_pattern = FcFontMatch(nullptr, pattern, &result); if (!font_pattern) { throw std::runtime_error(std::string("FcFontMatch() for ") + family + " returned nullptr"); } if (result != FcResultMatch) { FcPatternDestroy(font_pattern); throw FcResultException(result); } result = FcPatternGet(font_pattern, FC_FILE, 0, &font_value); if (result != FcResultMatch) { FcPatternDestroy(font_pattern); throw FcResultException(result); } filename = reinterpret_cast(font_value.u.s); FcPatternDestroy(font_pattern); return filename; } std::pair get_fonts() { if (FcInit() != FcTrue) { throw std::runtime_error("FcInit() returned FcFalse"); } std::string monospace_filename, sans_serif_filename; FcPattern* pattern = FcPatternCreate(); if (!pattern) { FcFini(); throw std::bad_alloc(); } try { sans_serif_filename = get_filename(pattern, "sans-serif"); } catch (const std::exception& e) { FcPatternDestroy(pattern); FcFini(); throw; } FcPatternDel(pattern, FC_FAMILY); try { monospace_filename = get_filename(pattern, "monospace"); } catch (const std::exception& e) { FcPatternDestroy(pattern); FcFini(); throw; } FcPatternDestroy(pattern); FcFini(); return std::make_pair(std::move(sans_serif_filename), std::move(monospace_filename)); }