Skip to content

Commit

Permalink
Add support for reading font paths from the registry
Browse files Browse the repository at this point in the history
  • Loading branch information
tgoyne committed Mar 14, 2014
1 parent 2f77bef commit 6c22e89
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 30 deletions.
90 changes: 64 additions & 26 deletions src/fcdir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ extern "C" {
#include <thread>
#include <vector>

#include <ShlObj.h>

#undef min

namespace fs = std::tr2::sys;
Expand Down Expand Up @@ -77,6 +79,35 @@ FcPatternVector add_fonts(std::vector<std::string> const& files, size_t start, s
return ret;
}

void index_fonts(std::vector<std::string>& files, FcFontSet *set,
FcBlanks *blanks, FcConfig *config) {
sort(begin(files), end(files));

auto thread_count = std::thread::hardware_concurrency();
auto slice_size = (files.size() + thread_count - 1) / thread_count;
std::vector<std::future<FcPatternVector>> futures;
for (size_t thread = 0; thread < thread_count; ++thread) {
futures.emplace_back(std::async(std::launch::async, [&, thread] {
auto end = std::min((thread + 1) * slice_size, files.size());
return add_fonts(files, thread * slice_size, end, blanks);
}));
}

FcPatternVector fonts;
fonts.reserve(files.size());
for (auto& future : futures) {
FcPatternVector vec = future.get();
move(begin(vec), end(vec), back_inserter(fonts));
}

for (auto& font : fonts) {
if (!FcConfigSubstitute(config, font.get(), FcMatchScan))
continue;
if (FcFontSetAdd(set, font.get()))
font.release();
}
}

FcBool FcFileScanFontConfig(FcFontSet *set, FcBlanks *blanks,
const FcChar8 *file, FcConfig *config) {
int count = 0;
Expand Down Expand Up @@ -120,40 +151,47 @@ FcBool FcDirScanConfig(FcFontSet *set, FcStrSet *dirs, FcBlanks *blanks,
if (!set && !dirs) return FcTrue;
if (!blanks) blanks = FcConfigGetBlanks(config);

auto dir_path = fc_path(dir);
if (!is_directory(dir_path)) return FcTrue;

std::vector<std::string> files;
for (auto const &file : fs::directory_iterator(dir_path)) {
if (is_regular(file.status())) files.push_back(file.path());
}
if (strcmp((const char *)dir, "WINDOWSREGISTRY") == 0) {
static const auto fonts_key_name = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";

sort(begin(files), end(files));
HKEY key;
auto ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fonts_key_name, 0, KEY_QUERY_VALUE, &key);
if (ret != ERROR_SUCCESS) return 0;

auto thread_count = std::thread::hardware_concurrency();
auto slice_size = (files.size() + thread_count - 1) / thread_count;
std::vector<std::future<FcPatternVector>> futures;
for (size_t thread = 0; thread < thread_count; ++thread) {
futures.emplace_back(std::async(std::launch::async, [&] {
auto end = std::min((thread + 1) * slice_size, files.size());
return add_fonts(files, thread * slice_size, end, blanks);
}));
}
char fdir[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_FONTS, NULL, 0, fdir);

FcPatternVector fonts;
fonts.reserve(files.size());
for (auto& future : futures) {
FcPatternVector vec = future.get();
move(begin(vec), end(vec), back_inserter(fonts));
std::tr2::sys::path font_dir(fdir);

for (DWORD i = 0;; ++i) {
char font_name[SHRT_MAX], font_filename[MAX_PATH];
DWORD name_len = sizeof(font_name);
DWORD data_len = sizeof(font_filename);

ret = RegEnumValueA(key, i, font_name, &name_len, NULL, NULL, reinterpret_cast<BYTE *>(font_filename), &data_len);
if (ret == ERROR_NO_MORE_ITEMS) break;
if (ret != ERROR_SUCCESS) continue;

std::tr2::sys::path font_path(font_filename);
if (!is_regular(font_path))
font_path = font_dir / font_path;
files.push_back(font_path.string());
}

RegCloseKey(key);
}
else {
auto dir_path = fc_path(dir);
if (!is_directory(dir_path)) return FcTrue;

for (auto& font : fonts) {
if (!FcConfigSubstitute(config, font.get(), FcMatchScan))
continue;
if (FcFontSetAdd(set, font.get()))
font.release();
for (auto const &file : fs::directory_iterator(dir_path)) {
if (is_regular(file.status())) files.push_back(file.path());
}
}

index_fonts(files, set, blanks, config);

return FcTrue;
}

Expand Down
6 changes: 2 additions & 4 deletions src/fcinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,9 @@ static FcConfig *FcInitFallbackConfig(void) {
FcConfig *config = FcConfigCreate();
if (!config) return NULL;

char dir[MAX_PATH + 12];
SHGetFolderPath(NULL, CSIDL_FONTS, NULL, 0, dir);

if (!FcConfigAddDir(config, (FcChar8 *)dir)) goto bail1;
if (!FcConfigAddDir(config, (FcChar8 *)"WINDOWSREGISTRY")) goto bail1;

char dir[MAX_PATH + 12];
SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, dir);
strcat(dir, "\\fontconfig");
if (!FcConfigAddCacheDir(config, (FcChar8 *)dir)) goto bail1;
Expand Down
22 changes: 22 additions & 0 deletions src/fcstat.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,28 @@ int FcStat(const FcChar8 *file, struct stat *statb) {
char *basename;
DWORD rc;

if (strcmp(file, "WINDOWSREGISTRY") == 0) {
HKEY key;
FILETIME ft;
ULARGE_INTEGER u;

DWORD res = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", 0,
KEY_QUERY_VALUE, &key);
if (res != ERROR_SUCCESS) return -1;

res = RegQueryInfoKey(key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &ft);
RegCloseKey(key);
if (res != ERROR_SUCCESS) return -1;

u.LowPart = ft.dwLowDateTime;
u.HighPart = ft.dwHighDateTime;
// shift to seconds since 2000ish to fit in 32-bit time_t
statb->st_mtime = (time_t)(u.QuadPart / 10000000 - 12614400000);
return 0;
}

if (!GetFileAttributesEx((LPCSTR)file, GetFileExInfoStandard, &wfad))
return -1;

Expand Down
4 changes: 4 additions & 0 deletions src/fcstr.c
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,10 @@ static void FcConvertDosPath(char *str) {
FcChar8 *FcStrCanonFilename(const FcChar8 *s) {
#ifdef _WIN32
FcChar8 full[FC_MAX_FILE_LEN + 2];

if (strcmp(s, "WINDOWSREGISTRY") == 0)
return strdup(s);

int size = GetFullPathName((LPCSTR)s, sizeof(full) - 1, (LPSTR)full, NULL);

if (size == 0) perror("GetFullPathName");
Expand Down

1 comment on commit 6c22e89

@tophf
Copy link

@tophf tophf commented on 6c22e89 May 19, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If fontconfig can also use/parse Type1 fonts, those are listed under a different registry path (...\Type 1 Installer\Type 1 Fonts instead of ...\Fonts)

Please sign in to comment.