99 lines
3.0 KiB
C++
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));
|
||
|
}
|