| /* | |
| * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| #include <windows.h> | |
| #include <strsafe.h> | |
| #include <stdio.h> | |
| #include <malloc.h> | |
| #include <jni.h> | |
| #include <jni_util.h> | |
| #include <sun_awt_Win32FontManager.h> | |
| #define BSIZE (max(512, MAX_PATH+1)) | |
| /* Typically all local references held by a JNI function are automatically | |
| * released by JVM when the function returns. However, there is a limit to the | |
| * number of local references that can remain active. If the local references | |
| * continue to grow, it could result in out of memory error. Henceforth, we | |
| * invoke DeleteLocalRef on objects that are no longer needed for execution in | |
| * the JNI function. | |
| */ | |
| #define DeleteLocalReference(env, jniRef) \ | |
| do { \ | |
| if (jniRef != NULL) { \ | |
| (*env)->DeleteLocalRef(env, jniRef); \ | |
| jniRef = NULL; \ | |
| } \ | |
| } while (0) | |
| JNIEXPORT jstring JNICALL Java_sun_awt_Win32FontManager_getFontPath(JNIEnv *env, jobject thiz, jboolean noType1) | |
| { | |
| char windir[BSIZE]; | |
| char sysdir[BSIZE]; | |
| char fontpath[BSIZE*2]; | |
| char *end; | |
| /* Locate fonts directories relative to the Windows System directory. | |
| * If Windows System location is different than the user's window | |
| * directory location, as in a shared Windows installation, | |
| * return both locations as potential font directories | |
| */ | |
| GetSystemDirectory(sysdir, BSIZE); | |
| end = strrchr(sysdir,'\\'); | |
| if (end && (stricmp(end,"\\System") || stricmp(end,"\\System32"))) { | |
| *end = 0; | |
| StringCchCatA(sysdir, BSIZE, "\\Fonts"); | |
| } | |
| GetWindowsDirectory(windir, BSIZE); | |
| if (strlen(windir) > BSIZE-7) { | |
| *windir = 0; | |
| } else { | |
| StringCchCatA(windir, BSIZE, "\\Fonts"); | |
| } | |
| StringCchCopyA(fontpath, BSIZE*2, sysdir); | |
| if (stricmp(sysdir,windir)) { | |
| StringCchCatA(fontpath, BSIZE*2, ";"); | |
| StringCchCatA(fontpath, BSIZE*2, windir); | |
| } | |
| return JNU_NewStringPlatform(env, fontpath); | |
| } | |
| /* The code below is used to obtain information from the windows font APIS | |
| * and registry on which fonts are available and what font files hold those | |
| * fonts. The results are used to speed font lookup. | |
| */ | |
| typedef struct GdiFontMapInfo { | |
| JNIEnv *env; | |
| jstring family; | |
| jobject fontToFamilyMap; | |
| jobject familyToFontListMap; | |
| jobject list; | |
| jmethodID putMID; | |
| jmethodID containsKeyMID; | |
| jclass arrayListClass; | |
| jmethodID arrayListCtr; | |
| jmethodID addMID; | |
| jmethodID toLowerCaseMID; | |
| jobject locale; | |
| } GdiFontMapInfo; | |
| /* Registry entry for fonts */ | |
| static const char FONTKEY_NT[] = | |
| "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; | |
| typedef struct CheckFamilyInfo { | |
| wchar_t *family; | |
| wchar_t* fullName; | |
| int isDifferent; | |
| } CheckFamilyInfo; | |
| static int CALLBACK CheckFontFamilyProcW( | |
| ENUMLOGFONTEXW *lpelfe, | |
| NEWTEXTMETRICEX *lpntme, | |
| int FontType, | |
| LPARAM lParam) | |
| { | |
| CheckFamilyInfo *info = (CheckFamilyInfo*)lParam; | |
| info->isDifferent = wcscmp(lpelfe->elfLogFont.lfFaceName, info->family); | |
| /* if (!info->isDifferent) { */ | |
| /* wprintf(LFor font %s expected family=%s instead got %s\n", */ | |
| /* lpelfe->elfFullName, */ | |
| /* info->family, */ | |
| /* lpelfe->elfLogFont.lfFaceName); */ | |
| /* fflush(stdout); */ | |
| /* } */ | |
| return 0; | |
| } | |
| /* This HDC is initialised and released in the populate family map | |
| * JNI entry point, and used within the call which would otherwise | |
| * create many DCs. | |
| */ | |
| static HDC screenDC = NULL; | |
| static int DifferentFamily(wchar_t *family, wchar_t* fullName) { | |
| LOGFONTW lfw; | |
| CheckFamilyInfo info; | |
| /* If fullName can't be stored in the struct, assume correct family */ | |
| if (wcslen((LPWSTR)fullName) >= LF_FACESIZE) { | |
| return 0; | |
| } | |
| memset(&info, 0, sizeof(CheckFamilyInfo)); | |
| info.family = family; | |
| info.fullName = fullName; | |
| info.isDifferent = 0; | |
| memset(&lfw, 0, sizeof(lfw)); | |
| StringCchCopyW(lfw.lfFaceName, LF_FACESIZE, fullName); | |
| lfw.lfCharSet = DEFAULT_CHARSET; | |
| EnumFontFamiliesExW(screenDC, &lfw, | |
| (FONTENUMPROCW)CheckFontFamilyProcW, | |
| (LPARAM)(&info), 0L); | |
| return info.isDifferent; | |
| } | |
| /* Callback for call to EnumFontFamiliesEx in the EnumFamilyNames function. | |
| * Expects to be called once for each face name in the family specified | |
| * in the call. We extract the full name for the font which is expected | |
| * to be in the "system encoding" and create canonical and lower case | |
| * Java strings for the name which are added to the maps. The lower case | |
| * name is used as key to the family name value in the font to family map, | |
| * the canonical name is one of the"list" of members of the family. | |
| */ | |
| static int CALLBACK EnumFontFacesInFamilyProcW( | |
| ENUMLOGFONTEXW *lpelfe, | |
| NEWTEXTMETRICEX *lpntme, | |
| int FontType, | |
| LPARAM lParam) | |
| { | |
| GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; | |
| JNIEnv *env = fmi->env; | |
| jstring fullname, fullnameLC; | |
| /* Exceptions indicate critical errors such that program cannot continue | |
| * with further execution. Henceforth, the function returns immediately | |
| * on pending exceptions. In these situations, the function also returns | |
| * 0 indicating windows API to stop further enumeration and callbacks. | |
| * | |
| * The JNI functions do not clear the pending exceptions. This allows the | |
| * caller (Java code) to check and handle exceptions in the best possible | |
| * way. | |
| */ | |
| if ((*env)->ExceptionCheck(env)) { | |
| return 0; | |
| } | |
| /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ | |
| if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { | |
| return 1; | |
| } | |
| /* Windows has font aliases and so may enumerate fonts from | |
| * the aliased family if any actual font of that family is installed. | |
| * To protect against it ignore fonts which aren't enumerated under | |
| * their true family. | |
| */ | |
| if (DifferentFamily(lpelfe->elfLogFont.lfFaceName, | |
| lpelfe->elfFullName)) { | |
| return 1; | |
| } | |
| fullname = (*env)->NewString(env, lpelfe->elfFullName, | |
| (jsize)wcslen((LPWSTR)lpelfe->elfFullName)); | |
| if (fullname == NULL) { | |
| (*env)->ExceptionClear(env); | |
| return 1; | |
| } | |
| (*env)->CallBooleanMethod(env, fmi->list, fmi->addMID, fullname); | |
| if ((*env)->ExceptionCheck(env)) { | |
| /* Delete the created reference before return */ | |
| DeleteLocalReference(env, fullname); | |
| return 0; | |
| } | |
| fullnameLC = (*env)->CallObjectMethod(env, fullname, | |
| fmi->toLowerCaseMID, fmi->locale); | |
| /* Delete the created reference after its usage */ | |
| DeleteLocalReference(env, fullname); | |
| if ((*env)->ExceptionCheck(env)) { | |
| return 0; | |
| } | |
| (*env)->CallObjectMethod(env, fmi->fontToFamilyMap, | |
| fmi->putMID, fullnameLC, fmi->family); | |
| /* Delete the created reference after its usage */ | |
| DeleteLocalReference(env, fullnameLC); | |
| if ((*env)->ExceptionCheck(env)) { | |
| return 0; | |
| } | |
| return 1; | |
| } | |
| /* Callback for EnumFontFamiliesEx in populateFontFileNameMap. | |
| * Expects to be called for every charset of every font family. | |
| * If this is the first time we have been called for this family, | |
| * add a new mapping to the familyToFontListMap from this family to a | |
| * list of its members. To populate that list, further enumerate all faces | |
| * in this family for the matched charset. This assumes that all fonts | |
| * in a family support the same charset, which is a fairly safe assumption | |
| * and saves time as the call we make here to EnumFontFamiliesEx will | |
| * enumerate the members of this family just once each. | |
| * Because we set fmi->list to be the newly created list the call back | |
| * can safely add to that list without a search. | |
| */ | |
| static int CALLBACK EnumFamilyNamesW( | |
| ENUMLOGFONTEXW *lpelfe, /* pointer to logical-font data */ | |
| NEWTEXTMETRICEX *lpntme, /* pointer to physical-font data */ | |
| int FontType, /* type of font */ | |
| LPARAM lParam ) /* application-defined data */ | |
| { | |
| GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; | |
| JNIEnv *env = fmi->env; | |
| jstring familyLC; | |
| size_t slen; | |
| LOGFONTW lfw; | |
| jboolean mapHasKey; | |
| /* Exceptions indicate critical errors such that program cannot continue | |
| * with further execution. Henceforth, the function returns immediately | |
| * on pending exceptions. In these situations, the function also returns | |
| * 0 indicating windows API to stop further enumeration and callbacks. | |
| * | |
| * The JNI functions do not clear the pending exceptions. This allows the | |
| * caller (Java code) to check and handle exceptions in the best possible | |
| * way. | |
| */ | |
| if ((*env)->ExceptionCheck(env)) { | |
| return 0; | |
| } | |
| /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ | |
| if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { | |
| return 1; | |
| } | |
| /* wprintf(L"FAMILY=%s charset=%d FULL=%s\n", */ | |
| /* lpelfe->elfLogFont.lfFaceName, */ | |
| /* lpelfe->elfLogFont.lfCharSet, */ | |
| /* lpelfe->elfFullName); */ | |
| /* fflush(stdout); */ | |
| /* Windows lists fonts which have a vmtx (vertical metrics) table twice. | |
| * Once using their normal name, and again preceded by '@'. These appear | |
| * in font lists in some windows apps, such as wordpad. We don't want | |
| * these so we skip any font where the first character is '@' | |
| */ | |
| if (lpelfe->elfLogFont.lfFaceName[0] == L'@') { | |
| return 1; | |
| } | |
| slen = wcslen(lpelfe->elfLogFont.lfFaceName); | |
| fmi->family = (*env)->NewString(env,lpelfe->elfLogFont.lfFaceName, (jsize)slen); | |
| if (fmi->family == NULL) { | |
| (*env)->ExceptionClear(env); | |
| return 1; | |
| } | |
| familyLC = (*env)->CallObjectMethod(env, fmi->family, | |
| fmi->toLowerCaseMID, fmi->locale); | |
| /* Delete the created reference after its usage */ | |
| if ((*env)->ExceptionCheck(env)) { | |
| DeleteLocalReference(env, fmi->family); | |
| return 0; | |
| } | |
| /* check if already seen this family with a different charset */ | |
| mapHasKey = (*env)->CallBooleanMethod(env, | |
| fmi->familyToFontListMap, | |
| fmi->containsKeyMID, | |
| familyLC); | |
| if ((*env)->ExceptionCheck(env)) { | |
| /* Delete the created references before return */ | |
| DeleteLocalReference(env, fmi->family); | |
| DeleteLocalReference(env, familyLC); | |
| return 0; | |
| } else if (mapHasKey) { | |
| /* Delete the created references before return */ | |
| DeleteLocalReference(env, fmi->family); | |
| DeleteLocalReference(env, familyLC); | |
| return 1; | |
| } | |
| fmi->list = (*env)->NewObject(env, | |
| fmi->arrayListClass, fmi->arrayListCtr, 4); | |
| if (fmi->list == NULL) { | |
| /* Delete the created references before return */ | |
| DeleteLocalReference(env, fmi->family); | |
| DeleteLocalReference(env, familyLC); | |
| return 0; | |
| } | |
| (*env)->CallObjectMethod(env, fmi->familyToFontListMap, | |
| fmi->putMID, familyLC, fmi->list); | |
| /* Delete the created reference after its usage */ | |
| DeleteLocalReference(env, familyLC); | |
| if ((*env)->ExceptionCheck(env)) { | |
| /* Delete the created reference before return */ | |
| DeleteLocalReference(env, fmi->family); | |
| DeleteLocalReference(env, fmi->list); | |
| return 0; | |
| } | |
| memset(&lfw, 0, sizeof(lfw)); | |
| StringCchCopyW(lfw.lfFaceName, LF_FACESIZE, lpelfe->elfLogFont.lfFaceName); | |
| lfw.lfCharSet = lpelfe->elfLogFont.lfCharSet; | |
| EnumFontFamiliesExW(screenDC, &lfw, | |
| (FONTENUMPROCW)EnumFontFacesInFamilyProcW, | |
| lParam, 0L); | |
| /* Delete the created reference after its usage in the enum function */ | |
| DeleteLocalReference(env, fmi->family); | |
| DeleteLocalReference(env, fmi->list); | |
| return 1; | |
| } | |
| /* It looks like TrueType fonts have " (TrueType)" tacked on the end of their | |
| * name, so we can try to use that to distinguish TT from other fonts. | |
| * However if a program "installed" a font in the registry the key may | |
| * not include that. We could also try to "pass" fonts which have no "(..)" | |
| * at the end. But that turns out to pass a few .FON files that MS supply. | |
| * If there's no parenthesized type string, we could next try to infer | |
| * the file type from the file name extension. Since the MS entries that | |
| * have no type string are very few, and have odd names like "MS-DOS CP 437" | |
| * and would never return a Java Font anyway its currently OK to put these | |
| * in the font map, although clearly the returned names must never percolate | |
| * up into a list of available fonts returned to the application. | |
| * Additionally for TTC font files the key looks like | |
| * Font 1 & Font 2 (TrueType) | |
| * or sometimes even : | |
| * Font 1 & Font 2 & Font 3 (TrueType) | |
| * Also if a Font has a name for this locale that name also | |
| * exists in the registry using the appropriate platform encoding. | |
| * What do we do then? | |
| * | |
| * Note: OpenType fonts seems to have " (TrueType)" suffix on Vista | |
| * but " (OpenType)" on XP. | |
| */ | |
| static BOOL RegistryToBaseTTNameW(LPWSTR name) { | |
| static const wchar_t TTSUFFIX[] = L" (TrueType)"; | |
| static const wchar_t OTSUFFIX[] = L" (OpenType)"; | |
| size_t TTSLEN = wcslen(TTSUFFIX); | |
| wchar_t *suffix; | |
| size_t len = wcslen(name); | |
| if (len == 0) { | |
| return FALSE; | |
| } | |
| if (name[len-1] != L')') { | |
| return FALSE; | |
| } | |
| if (len <= TTSLEN) { | |
| return FALSE; | |
| } | |
| /* suffix length is the same for truetype and opentype fonts */ | |
| suffix = name + (len - TTSLEN); | |
| if (wcscmp(suffix, TTSUFFIX) == 0 || wcscmp(suffix, OTSUFFIX) == 0) { | |
| suffix[0] = L'\0'; /* truncate name */ | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| static void registerFontW(GdiFontMapInfo *fmi, jobject fontToFileMap, | |
| LPWSTR name, LPWSTR data) { | |
| wchar_t *ptr1, *ptr2; | |
| jstring fontStr; | |
| jstring fontStrLC; | |
| JNIEnv *env = fmi->env; | |
| size_t dslen = wcslen(data); | |
| jstring fileStr = (*env)->NewString(env, data, (jsize)dslen); | |
| if (fileStr == NULL) { | |
| (*env)->ExceptionClear(env); | |
| return; | |
| } | |
| /* TTC or ttc means it may be a collection. Need to parse out | |
| * multiple font face names separated by " & " | |
| * By only doing this for fonts which look like collections based on | |
| * file name we are adhering to MS recommendations for font file names | |
| * so it seems that we can be sure that this identifies precisely | |
| * the MS-supplied truetype collections. | |
| * This avoids any potential issues if a TTF file happens to have | |
| * a & in the font name (I can't find anything which prohibits this) | |
| * and also means we only parse the key in cases we know to be | |
| * worthwhile. | |
| */ | |
| if ((data[dslen-1] == L'C' || data[dslen-1] == L'c') && | |
| (ptr1 = wcsstr(name, L" & ")) != NULL) { | |
| ptr1+=3; | |
| while (ptr1 >= name) { /* marginally safer than while (true) */ | |
| while ((ptr2 = wcsstr(ptr1, L" & ")) != NULL) { | |
| ptr1 = ptr2+3; | |
| } | |
| fontStr = (*env)->NewString(env, ptr1, (jsize)wcslen(ptr1)); | |
| if (fontStr == NULL) { | |
| (*env)->ExceptionClear(env); | |
| /* Delete the created reference before return */ | |
| DeleteLocalReference(env, fileStr); | |
| return; | |
| } | |
| fontStrLC = (*env)->CallObjectMethod(env, fontStr, | |
| fmi->toLowerCaseMID, | |
| fmi->locale); | |
| /* Delete the created reference after its usage */ | |
| DeleteLocalReference(env, fontStr); | |
| if ((*env)->ExceptionCheck(env)) { | |
| /* Delete the created reference before return */ | |
| DeleteLocalReference(env, fileStr); | |
| return; | |
| } | |
| (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, | |
| fontStrLC, fileStr); | |
| /* Delete the reference after its usage */ | |
| DeleteLocalReference(env, fontStrLC); | |
| if ((*env)->ExceptionCheck(env)) { | |
| /* Delete the created reference before return */ | |
| DeleteLocalReference(env, fileStr); | |
| return; | |
| } | |
| if (ptr1 == name) { | |
| break; | |
| } else { | |
| *(ptr1-3) = L'\0'; | |
| ptr1 = name; | |
| } | |
| } | |
| } else { | |
| fontStr = (*env)->NewString(env, name, (jsize)wcslen(name)); | |
| if (fontStr == NULL) { | |
| (*env)->ExceptionClear(env); | |
| /* Delete the created reference before return */ | |
| DeleteLocalReference(env, fileStr); | |
| return; | |
| } | |
| fontStrLC = (*env)->CallObjectMethod(env, fontStr, | |
| fmi->toLowerCaseMID, fmi->locale); | |
| /* Delete the created reference after its usage */ | |
| DeleteLocalReference(env, fontStr); | |
| if ((*env)->ExceptionCheck(env)) { | |
| /* Delete the created reference before return */ | |
| DeleteLocalReference(env, fileStr); | |
| return; | |
| } | |
| (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, | |
| fontStrLC, fileStr); | |
| /* Delete the created reference after its usage */ | |
| DeleteLocalReference(env, fontStrLC); | |
| if ((*env)->ExceptionCheck(env)) { | |
| /* Delete the created reference before return */ | |
| DeleteLocalReference(env, fileStr); | |
| return; | |
| } | |
| } | |
| /* Delete the created reference after its usage */ | |
| DeleteLocalReference(env, fileStr); | |
| } | |
| static void populateFontFileNameFromRegistryKey(HKEY regKey, | |
| GdiFontMapInfo *fmi, | |
| jobject fontToFileMap) | |
| { | |
| DWORD type; | |
| LONG ret; | |
| HKEY hkeyFonts; | |
| DWORD nval; | |
| DWORD dwNumValues, dwMaxValueNameLen, dwMaxValueDataLen; | |
| /* Use the windows registry to map font names to files */ | |
| ret = RegOpenKeyEx(regKey, | |
| FONTKEY_NT, 0L, KEY_READ, &hkeyFonts); | |
| if (ret != ERROR_SUCCESS) { | |
| return; | |
| } | |
| ret = RegQueryInfoKeyW(hkeyFonts, NULL, NULL, NULL, NULL, NULL, NULL, | |
| &dwNumValues, &dwMaxValueNameLen, | |
| &dwMaxValueDataLen, NULL, NULL); | |
| if (ret != ERROR_SUCCESS) { | |
| RegCloseKey(hkeyFonts); | |
| return; | |
| } | |
| dwMaxValueNameLen++; /* Account for NULL-terminator */ | |
| wchar_t *wname = (wchar_t*)malloc(dwMaxValueNameLen * sizeof(wchar_t)); | |
| wchar_t *data = (wchar_t*)malloc(dwMaxValueDataLen); | |
| for (nval = 0; nval < dwNumValues; nval++ ) { | |
| DWORD dwNameSize = dwMaxValueNameLen; | |
| DWORD dwDataValueSize = dwMaxValueDataLen; | |
| ret = RegEnumValueW(hkeyFonts, nval, wname, &dwNameSize, | |
| NULL, &type, (LPBYTE)data, &dwDataValueSize); | |
| if (ret != ERROR_SUCCESS) { | |
| break; | |
| } | |
| if (type != REG_SZ) { /* REG_SZ means a null-terminated string */ | |
| continue; | |
| } | |
| if (!RegistryToBaseTTNameW(wname) ) { | |
| /* If the filename ends with ".ttf" or ".otf" also accept it. | |
| * Not expecting to need to do this for .ttc files. | |
| * Also note this code is not mirrored in the "A" (win9x) path. | |
| */ | |
| LPWSTR dot = wcsrchr(data, L'.'); | |
| if (dot == NULL || ((wcsicmp(dot, L".ttf") != 0) | |
| && (wcsicmp(dot, L".otf") != 0))) { | |
| continue; /* not a TT font... */ | |
| } | |
| } | |
| registerFontW(fmi, fontToFileMap, wname, data); | |
| } | |
| free(wname); | |
| free(data); | |
| RegCloseKey(hkeyFonts); | |
| } | |
| /* Obtain all the fontname -> filename mappings. | |
| * This is called once and the results returned to Java code which can | |
| * use it for lookups to reduce or avoid the need to search font files. | |
| */ | |
| JNIEXPORT void JNICALL | |
| Java_sun_awt_Win32FontManager_populateFontFileNameMap0 | |
| (JNIEnv *env, jclass obj, jobject fontToFileMap, | |
| jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale) | |
| { | |
| jclass classIDHashMap; | |
| jclass classIDString; | |
| jmethodID putMID; | |
| GdiFontMapInfo fmi; | |
| LOGFONTW lfw; | |
| /* Check we were passed all the maps we need, and do lookup of | |
| * methods for JNI up-calls | |
| */ | |
| if (fontToFileMap == NULL || | |
| fontToFamilyMap == NULL || | |
| familyToFontListMap == NULL) { | |
| return; | |
| } | |
| classIDHashMap = (*env)->FindClass(env, "java/util/HashMap"); | |
| if (classIDHashMap == NULL) { | |
| return; | |
| } | |
| putMID = (*env)->GetMethodID(env, classIDHashMap, "put", | |
| "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); | |
| if (putMID == NULL) { | |
| return; | |
| } | |
| fmi.env = env; | |
| fmi.fontToFamilyMap = fontToFamilyMap; | |
| fmi.familyToFontListMap = familyToFontListMap; | |
| fmi.putMID = putMID; | |
| fmi.locale = locale; | |
| fmi.containsKeyMID = (*env)->GetMethodID(env, classIDHashMap, | |
| "containsKey", | |
| "(Ljava/lang/Object;)Z"); | |
| if (fmi.containsKeyMID == NULL) { | |
| return; | |
| } | |
| fmi.arrayListClass = (*env)->FindClass(env, "java/util/ArrayList"); | |
| if (fmi.arrayListClass == NULL) { | |
| return; | |
| } | |
| fmi.arrayListCtr = (*env)->GetMethodID(env, fmi.arrayListClass, | |
| "<init>", "(I)V"); | |
| if (fmi.arrayListCtr == NULL) { | |
| return; | |
| } | |
| fmi.addMID = (*env)->GetMethodID(env, fmi.arrayListClass, | |
| "add", "(Ljava/lang/Object;)Z"); | |
| if (fmi.addMID == NULL) { | |
| return; | |
| } | |
| classIDString = (*env)->FindClass(env, "java/lang/String"); | |
| if (classIDString == NULL) { | |
| return; | |
| } | |
| fmi.toLowerCaseMID = | |
| (*env)->GetMethodID(env, classIDString, "toLowerCase", | |
| "(Ljava/util/Locale;)Ljava/lang/String;"); | |
| if (fmi.toLowerCaseMID == NULL) { | |
| return; | |
| } | |
| screenDC = GetDC(NULL); | |
| if (screenDC == NULL) { | |
| return; | |
| } | |
| /* Enumerate fonts via GDI to build maps of fonts and families */ | |
| memset(&lfw, 0, sizeof(lfw)); | |
| lfw.lfCharSet = DEFAULT_CHARSET; /* all charsets */ | |
| StringCchCopyW(lfw.lfFaceName, LF_FACESIZE, L""); /* one face per family (CHECK) */ | |
| EnumFontFamiliesExW(screenDC, &lfw, | |
| (FONTENUMPROCW)EnumFamilyNamesW, | |
| (LPARAM)(&fmi), 0L); | |
| /* Starting from Windows 10 Preview Build 17704 | |
| * fonts are installed into user's home folder by default, | |
| * and are listed in user's registry section | |
| */ | |
| populateFontFileNameFromRegistryKey(HKEY_CURRENT_USER, &fmi, fontToFileMap); | |
| populateFontFileNameFromRegistryKey(HKEY_LOCAL_MACHINE, &fmi, fontToFileMap); | |
| ReleaseDC(NULL, screenDC); | |
| screenDC = NULL; | |
| } |