obs-studio/plugins/text-freetype2/find-font-windows.c
jp9000 f53df7da64 clang-format: Apply formatting
Code submissions have continually suffered from formatting
inconsistencies that constantly have to be addressed.  Using
clang-format simplifies this by making code formatting more consistent,
and allows automation of the code formatting so that maintainers can
focus more on the code itself instead of code formatting.
2019-06-23 23:49:10 -07:00

277 lines
6.9 KiB
C

#include <util/dstr.h>
#include <util/darray.h>
#include <util/crc32.h>
#include "find-font.h"
#include "text-freetype2.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
extern DARRAY(struct font_path_info) font_list;
extern void save_font_list(void);
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, (char *)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,
(char *)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;
}
uint32_t get_font_checksum(void)
{
uint32_t checksum = 0;
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 0;
}
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 {
checksum = calc_crc32(checksum, &wfd.ftLastWriteTime,
sizeof(FILETIME));
checksum = calc_crc32(checksum, wfd.cFileName,
strlen(wfd.cFileName));
} while (FindNextFileA(handle, &wfd));
FindClose(handle);
free_string:
dstr_free(&path);
return checksum;
}
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);
save_font_list();
free_string:
dstr_free(&path);
}