logmeow/fonts.cpp

99 lines
3.0 KiB
C++

#include <string>
#include <utility>
#include <exception>
#include <stdexcept>
#include <fontconfig/fontconfig.h>
#include <cstdio>
#include <cstdlib>
#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<const FcChar8*>(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<const char*>(font_value.u.s);
FcPatternDestroy(font_pattern);
return filename;
}
std::pair<std::string, std::string> 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));
}