#include #include #include "find-font.h" #include "text-freetype2.h" #define WIN32_LEAN_AND_MEAN #include #include #include extern DARRAY(struct font_path_info) font_list; struct mac_font_mapping { unsigned short encoding_id; unsigned short language_id; unsigned int code_page; }; #define TT_MAC_LANGID_ANY 0xFFFF static const struct mac_font_mapping mac_codes[] = { {TT_MAC_ID_ROMAN, TT_MAC_LANGID_ENGLISH, 10000}, {TT_MAC_ID_ROMAN, TT_MAC_LANGID_ICELANDIC, 10079}, {TT_MAC_ID_ROMAN, TT_MAC_LANGID_TURKISH, 10081}, {TT_MAC_ID_ROMAN, TT_MAC_LANGID_POLISH, 10029}, {TT_MAC_ID_ROMAN, TT_MAC_LANGID_ROMANIAN, 10010}, {TT_MAC_ID_ROMAN, TT_MAC_LANGID_CZECH, 10029}, {TT_MAC_ID_ROMAN, TT_MAC_LANGID_SLOVAK, 10029}, {TT_MAC_ID_ROMAN, TT_MAC_LANGID_ANY, 10000}, {TT_MAC_ID_JAPANESE, TT_MAC_LANGID_JAPANESE, 932}, {TT_MAC_ID_JAPANESE, TT_MAC_LANGID_ANY, 932}, {TT_MAC_ID_TRADITIONAL_CHINESE,TT_MAC_LANGID_CHINESE_SIMPLIFIED, 950}, {TT_MAC_ID_TRADITIONAL_CHINESE,TT_MAC_LANGID_ANY, 950}, {TT_MAC_ID_KOREAN, TT_MAC_LANGID_KOREAN, 51949}, {TT_MAC_ID_KOREAN, TT_MAC_LANGID_ANY, 51949}, {TT_MAC_ID_ARABIC, TT_MAC_LANGID_ARABIC, 10004}, {TT_MAC_ID_ARABIC, TT_MAC_LANGID_URDU, 0}, {TT_MAC_ID_ARABIC, TT_MAC_LANGID_FARSI, 0}, {TT_MAC_ID_ARABIC, TT_MAC_LANGID_ANY, 10004}, {TT_MAC_ID_HEBREW, TT_MAC_LANGID_HEBREW, 10005}, {TT_MAC_ID_HEBREW, TT_MAC_LANGID_ANY, 10005}, {TT_MAC_ID_GREEK, TT_MAC_LANGID_ANY, 10006}, {TT_MAC_ID_RUSSIAN, TT_MAC_LANGID_ANY, 10007}, {TT_MAC_ID_DEVANAGARI, TT_MAC_LANGID_ANY, 0}, {TT_MAC_ID_GURMUKHI, TT_MAC_LANGID_ANY, 0}, {TT_MAC_ID_GUJARATI, TT_MAC_LANGID_ANY, 0}, {TT_MAC_ID_SIMPLIFIED_CHINESE, TT_MAC_LANGID_CHINESE_SIMPLIFIED, 936}, {TT_MAC_ID_SIMPLIFIED_CHINESE, TT_MAC_LANGID_ANY, 936} }; unsigned int iso_codes[] = { 20127, 0, 28591 }; unsigned int ms_codes[] = { 1201, 1201, 932, 0, 950, 0, 0, 0, 0, 0, 1201 }; static const size_t mac_code_count = sizeof(mac_codes) / sizeof(mac_codes[0]); static const size_t iso_code_count = sizeof(iso_codes) / sizeof(iso_codes[0]); static const size_t ms_code_count = sizeof(ms_codes) / sizeof(ms_codes[0]); static unsigned int get_mac_code(uint16_t encoding_id, uint16_t language_id) { for (size_t i = 0; i < mac_code_count; i++) { const struct mac_font_mapping *mac_code = &mac_codes[i]; if (mac_code->encoding_id == encoding_id && mac_code->language_id == language_id) return mac_code->code_page; } return 0; } static unsigned int get_code_page_for_font(uint16_t platform_id, uint16_t encoding_id, uint16_t language_id) { unsigned int ret; switch (platform_id) { case TT_PLATFORM_APPLE_UNICODE: return 1201; case TT_PLATFORM_MACINTOSH: ret = get_mac_code(encoding_id, language_id); if (!ret) ret = get_mac_code(encoding_id, TT_MAC_LANGID_ANY); return ret; case TT_PLATFORM_ISO: if (encoding_id < iso_code_count) return iso_codes[encoding_id]; break; case TT_PLATFORM_MICROSOFT: if (encoding_id < ms_code_count) return ms_codes[encoding_id]; break; } return 0; } static char *wide_to_utf8(const wchar_t *str, size_t len) { size_t utf8_len; char *utf8_str = NULL; utf8_len = (size_t)WideCharToMultiByte(CP_UTF8, 0, str, (int)len, NULL, 0, NULL, false); if (utf8_len) { utf8_str = bzalloc(utf8_len + 1); utf8_len = (size_t)WideCharToMultiByte(CP_UTF8, 0, str, (int)len, utf8_str, (int)utf8_len + 1, NULL, false); if (!utf8_len) { bfree(utf8_str); utf8_str = NULL; } } return utf8_str; } static char *convert_utf16_be_to_utf8(FT_SfntName *sfnt_name) { size_t utf16_len = sfnt_name->string_len / 2; wchar_t *utf16_str = malloc((utf16_len + 1) * sizeof(wchar_t)); char *utf8_str = NULL; utf16_str[utf16_len] = 0; /* convert to little endian */ for (size_t i = 0; i < utf16_len; i++) { size_t pos = i * 2; wchar_t ch = *(wchar_t *)&sfnt_name->string[pos]; utf16_str[i] = ((ch >> 8) & 0xFF) | ((ch << 8) & 0xFF00); } utf8_str = wide_to_utf8(utf16_str, utf16_len); free(utf16_str); return utf8_str; } char *sfnt_name_to_utf8(FT_SfntName *sfnt_name) { unsigned int code_page = get_code_page_for_font( sfnt_name->platform_id, sfnt_name->encoding_id, sfnt_name->language_id); char *utf8_str = NULL; wchar_t *utf16_str; size_t utf16_len; if (code_page == 1201) return convert_utf16_be_to_utf8(sfnt_name); else if (code_page == 0) return NULL; utf16_len = MultiByteToWideChar(code_page, 0, sfnt_name->string, sfnt_name->string_len, NULL, 0); if (utf16_len) { utf16_str = malloc((utf16_len + 1) * sizeof(wchar_t)); utf16_len = MultiByteToWideChar(code_page, 0, sfnt_name->string, sfnt_name->string_len, utf16_str, (int)utf16_len); if (utf16_len) { utf16_str[utf16_len] = 0; utf8_str = wide_to_utf8(utf16_str, utf16_len); } free(utf16_str); } return utf8_str; } void load_os_font_list(void) { struct dstr path = {0}; HANDLE handle; WIN32_FIND_DATAA wfd; dstr_reserve(&path, MAX_PATH); HRESULT res = SHGetFolderPathA(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, path.array); if (res != S_OK) { blog(LOG_WARNING, "Error finding windows font folder"); return; } path.len = strlen(path.array); dstr_cat(&path, "\\*.*"); handle = FindFirstFileA(path.array, &wfd); if (handle == INVALID_HANDLE_VALUE) goto free_string; dstr_resize(&path, path.len - 4); do { struct dstr full_path = {0}; FT_Face face; FT_Long idx = 0; FT_Long max_faces = 1; if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; dstr_copy_dstr(&full_path, &path); dstr_cat(&full_path, "\\"); dstr_cat(&full_path, wfd.cFileName); while (idx < max_faces) { FT_Error ret = FT_New_Face(ft2_lib, full_path.array, idx, &face); if (ret != 0) break; build_font_path_info(face, idx++, full_path.array); max_faces = face->num_faces; FT_Done_Face(face); } dstr_free(&full_path); } while (FindNextFileA(handle, &wfd)); FindClose(handle); free_string: dstr_free(&path); }