1 /* 2 * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <windows.h> 27 #include <stdio.h> 28 29 #include <jni.h> 30 #include <jni_util.h> 31 #include <sun_awt_Win32FontManager.h> 32 33 #define BSIZE (max(512, MAX_PATH+1)) 34 35 /* Typically all local references held by a JNI function are automatically 36 * released by JVM when the function returns. However, there is a limit to the 37 * number of local references that can remain active. If the local references 38 * continue to grow, it could result in out of memory error. Henceforth, we 39 * invoke DeleteLocalRef on objects that are no longer needed for execution in 40 * the JNI function. 41 */ 42 #define DeleteLocalReference(env, jniRef) \ 43 do { \ 44 if (jniRef != NULL) { \ 45 (*env)->DeleteLocalRef(env, jniRef); \ 46 jniRef = NULL; \ 47 } \ 48 } while (0) 49 50 JNIEXPORT jstring JNICALL Java_sun_awt_Win32FontManager_getFontPath(JNIEnv *env, jobject thiz, jboolean noType1) 51 { 52 char windir[BSIZE]; 53 char sysdir[BSIZE]; 54 char fontpath[BSIZE*2]; 55 char *end; 56 57 /* Locate fonts directories relative to the Windows System directory. 58 * If Windows System location is different than the user's window 59 * directory location, as in a shared Windows installation, 60 * return both locations as potential font directories 61 */ 62 GetSystemDirectory(sysdir, BSIZE); 63 end = strrchr(sysdir,'\\'); 64 if (end && (stricmp(end,"\\System") || stricmp(end,"\\System32"))) { 65 *end = 0; 66 strcat(sysdir, "\\Fonts"); 67 } 68 69 GetWindowsDirectory(windir, BSIZE); 70 if (strlen(windir) > BSIZE-7) { 71 *windir = 0; 72 } else { 73 strcat(windir, "\\Fonts"); 74 } 75 76 strcpy(fontpath,sysdir); 77 if (stricmp(sysdir,windir)) { 78 strcat(fontpath,";"); 79 strcat(fontpath,windir); 80 } 81 82 return JNU_NewStringPlatform(env, fontpath); 83 } 84 85 /* The code below is used to obtain information from the windows font APIS 86 * and registry on which fonts are available and what font files hold those 87 * fonts. The results are used to speed font lookup. 88 */ 89 90 typedef struct GdiFontMapInfo { 91 JNIEnv *env; 92 jstring family; 93 jobject fontToFamilyMap; 94 jobject familyToFontListMap; 95 jobject list; 96 jmethodID putMID; 97 jmethodID containsKeyMID; 98 jclass arrayListClass; 99 jmethodID arrayListCtr; 100 jmethodID addMID; 101 jmethodID toLowerCaseMID; 102 jobject locale; 103 } GdiFontMapInfo; 104 105 /* Registry entry for fonts */ 106 static const char FONTKEY_NT[] = 107 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; 108 109 typedef struct CheckFamilyInfo { 110 wchar_t *family; 111 wchar_t* fullName; 112 int isDifferent; 113 } CheckFamilyInfo; 114 115 static int CALLBACK CheckFontFamilyProcW( 116 ENUMLOGFONTEXW *lpelfe, 117 NEWTEXTMETRICEX *lpntme, 118 int FontType, 119 LPARAM lParam) 120 { 121 CheckFamilyInfo *info = (CheckFamilyInfo*)lParam; 122 info->isDifferent = wcscmp(lpelfe->elfLogFont.lfFaceName, info->family); 123 124 /* if (!info->isDifferent) { */ 125 /* wprintf(LFor font %s expected family=%s instead got %s\n", */ 126 /* lpelfe->elfFullName, */ 127 /* info->family, */ 128 /* lpelfe->elfLogFont.lfFaceName); */ 129 /* fflush(stdout); */ 130 /* } */ 131 return 0; 132 } 133 134 /* This HDC is initialised and released in the populate family map 135 * JNI entry point, and used within the call which would otherwise 136 * create many DCs. 137 */ 138 static HDC screenDC = NULL; 139 140 static int DifferentFamily(wchar_t *family, wchar_t* fullName) { 141 LOGFONTW lfw; 142 CheckFamilyInfo info; 143 144 /* If fullName can't be stored in the struct, assume correct family */ 145 if (wcslen((LPWSTR)fullName) >= LF_FACESIZE) { 146 return 0; 147 } 148 149 memset(&info, 0, sizeof(CheckFamilyInfo)); 150 info.family = family; 151 info.fullName = fullName; 152 info.isDifferent = 0; 153 154 memset(&lfw, 0, sizeof(lfw)); 155 wcscpy(lfw.lfFaceName, fullName); 156 lfw.lfCharSet = DEFAULT_CHARSET; 157 EnumFontFamiliesExW(screenDC, &lfw, 158 (FONTENUMPROCW)CheckFontFamilyProcW, 159 (LPARAM)(&info), 0L); 160 161 return info.isDifferent; 162 } 163 164 /* Callback for call to EnumFontFamiliesEx in the EnumFamilyNames function. 165 * Expects to be called once for each face name in the family specified 166 * in the call. We extract the full name for the font which is expected 167 * to be in the "system encoding" and create canonical and lower case 168 * Java strings for the name which are added to the maps. The lower case 169 * name is used as key to the family name value in the font to family map, 170 * the canonical name is one of the"list" of members of the family. 171 */ 172 static int CALLBACK EnumFontFacesInFamilyProcW( 173 ENUMLOGFONTEXW *lpelfe, 174 NEWTEXTMETRICEX *lpntme, 175 int FontType, 176 LPARAM lParam) 177 { 178 GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; 179 JNIEnv *env = fmi->env; 180 jstring fullname, fullnameLC; 181 182 /* Exceptions indicate critical errors such that program cannot continue 183 * with further execution. Henceforth, the function returns immediately 184 * on pending exceptions. In these situations, the function also returns 185 * 0 indicating windows API to stop further enumeration and callbacks. 186 * 187 * The JNI functions do not clear the pending exceptions. This allows the 188 * caller (Java code) to check and handle exceptions in the best possible 189 * way. 190 */ 191 if ((*env)->ExceptionCheck(env)) { 192 return 0; 193 } 194 195 /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ 196 if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { 197 return 1; 198 } 199 200 /* Windows has font aliases and so may enumerate fonts from 201 * the aliased family if any actual font of that family is installed. 202 * To protect against it ignore fonts which aren't enumerated under 203 * their true family. 204 */ 205 if (DifferentFamily(lpelfe->elfLogFont.lfFaceName, 206 lpelfe->elfFullName)) { 207 return 1; 208 } 209 210 fullname = (*env)->NewString(env, lpelfe->elfFullName, 211 (jsize)wcslen((LPWSTR)lpelfe->elfFullName)); 212 if (fullname == NULL) { 213 (*env)->ExceptionClear(env); 214 return 1; 215 } 216 217 (*env)->CallBooleanMethod(env, fmi->list, fmi->addMID, fullname); 218 if ((*env)->ExceptionCheck(env)) { 219 /* Delete the created reference before return */ 220 DeleteLocalReference(env, fullname); 221 return 0; 222 } 223 224 fullnameLC = (*env)->CallObjectMethod(env, fullname, 225 fmi->toLowerCaseMID, fmi->locale); 226 /* Delete the created reference after its usage */ 227 DeleteLocalReference(env, fullname); 228 if ((*env)->ExceptionCheck(env)) { 229 return 0; 230 } 231 232 (*env)->CallObjectMethod(env, fmi->fontToFamilyMap, 233 fmi->putMID, fullnameLC, fmi->family); 234 /* Delete the created reference after its usage */ 235 DeleteLocalReference(env, fullnameLC); 236 if ((*env)->ExceptionCheck(env)) { 237 return 0; 238 } 239 240 return 1; 241 } 242 243 /* Callback for EnumFontFamiliesEx in populateFontFileNameMap. 244 * Expects to be called for every charset of every font family. 245 * If this is the first time we have been called for this family, 246 * add a new mapping to the familyToFontListMap from this family to a 247 * list of its members. To populate that list, further enumerate all faces 248 * in this family for the matched charset. This assumes that all fonts 249 * in a family support the same charset, which is a fairly safe assumption 250 * and saves time as the call we make here to EnumFontFamiliesEx will 251 * enumerate the members of this family just once each. 252 * Because we set fmi->list to be the newly created list the call back 253 * can safely add to that list without a search. 254 */ 255 static int CALLBACK EnumFamilyNamesW( 256 ENUMLOGFONTEXW *lpelfe, /* pointer to logical-font data */ 257 NEWTEXTMETRICEX *lpntme, /* pointer to physical-font data */ 258 int FontType, /* type of font */ 259 LPARAM lParam ) /* application-defined data */ 260 { 261 GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; 262 JNIEnv *env = fmi->env; 263 jstring familyLC; 264 size_t slen; 265 LOGFONTW lfw; 266 jboolean mapHasKey; 267 268 /* Exceptions indicate critical errors such that program cannot continue 269 * with further execution. Henceforth, the function returns immediately 270 * on pending exceptions. In these situations, the function also returns 271 * 0 indicating windows API to stop further enumeration and callbacks. 272 * 273 * The JNI functions do not clear the pending exceptions. This allows the 274 * caller (Java code) to check and handle exceptions in the best possible 275 * way. 276 */ 277 if ((*env)->ExceptionCheck(env)) { 278 return 0; 279 } 280 281 /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ 282 if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { 283 return 1; 284 } 285 /* wprintf(L"FAMILY=%s charset=%d FULL=%s\n", */ 286 /* lpelfe->elfLogFont.lfFaceName, */ 287 /* lpelfe->elfLogFont.lfCharSet, */ 288 /* lpelfe->elfFullName); */ 289 /* fflush(stdout); */ 290 291 /* Windows lists fonts which have a vmtx (vertical metrics) table twice. 292 * Once using their normal name, and again preceded by '@'. These appear 293 * in font lists in some windows apps, such as wordpad. We don't want 294 * these so we skip any font where the first character is '@' 295 */ 296 if (lpelfe->elfLogFont.lfFaceName[0] == L'@') { 297 return 1; 298 } 299 slen = wcslen(lpelfe->elfLogFont.lfFaceName); 300 fmi->family = (*env)->NewString(env,lpelfe->elfLogFont.lfFaceName, (jsize)slen); 301 if (fmi->family == NULL) { 302 (*env)->ExceptionClear(env); 303 return 1; 304 } 305 306 familyLC = (*env)->CallObjectMethod(env, fmi->family, 307 fmi->toLowerCaseMID, fmi->locale); 308 /* Delete the created reference after its usage */ 309 if ((*env)->ExceptionCheck(env)) { 310 DeleteLocalReference(env, fmi->family); 311 return 0; 312 } 313 314 /* check if already seen this family with a different charset */ 315 mapHasKey = (*env)->CallBooleanMethod(env, 316 fmi->familyToFontListMap, 317 fmi->containsKeyMID, 318 familyLC); 319 if ((*env)->ExceptionCheck(env)) { 320 /* Delete the created references before return */ 321 DeleteLocalReference(env, fmi->family); 322 DeleteLocalReference(env, familyLC); 323 return 0; 324 } else if (mapHasKey) { 325 /* Delete the created references before return */ 326 DeleteLocalReference(env, fmi->family); 327 DeleteLocalReference(env, familyLC); 328 return 1; 329 } 330 331 fmi->list = (*env)->NewObject(env, 332 fmi->arrayListClass, fmi->arrayListCtr, 4); 333 if (fmi->list == NULL) { 334 /* Delete the created references before return */ 335 DeleteLocalReference(env, fmi->family); 336 DeleteLocalReference(env, familyLC); 337 return 0; 338 } 339 340 (*env)->CallObjectMethod(env, fmi->familyToFontListMap, 341 fmi->putMID, familyLC, fmi->list); 342 /* Delete the created reference after its usage */ 343 DeleteLocalReference(env, familyLC); 344 if ((*env)->ExceptionCheck(env)) { 345 /* Delete the created reference before return */ 346 DeleteLocalReference(env, fmi->family); 347 DeleteLocalReference(env, fmi->list); 348 return 0; 349 } 350 351 memset(&lfw, 0, sizeof(lfw)); 352 wcscpy(lfw.lfFaceName, lpelfe->elfLogFont.lfFaceName); 353 lfw.lfCharSet = lpelfe->elfLogFont.lfCharSet; 354 EnumFontFamiliesExW(screenDC, &lfw, 355 (FONTENUMPROCW)EnumFontFacesInFamilyProcW, 356 lParam, 0L); 357 358 /* Delete the created reference after its usage in the enum function */ 359 DeleteLocalReference(env, fmi->family); 360 DeleteLocalReference(env, fmi->list); 361 return 1; 362 } 363 364 /* It looks like TrueType fonts have " (TrueType)" tacked on the end of their 365 * name, so we can try to use that to distinguish TT from other fonts. 366 * However if a program "installed" a font in the registry the key may 367 * not include that. We could also try to "pass" fonts which have no "(..)" 368 * at the end. But that turns out to pass a few .FON files that MS supply. 369 * If there's no parenthesized type string, we could next try to infer 370 * the file type from the file name extension. Since the MS entries that 371 * have no type string are very few, and have odd names like "MS-DOS CP 437" 372 * and would never return a Java Font anyway its currently OK to put these 373 * in the font map, although clearly the returned names must never percolate 374 * up into a list of available fonts returned to the application. 375 * Additionally for TTC font files the key looks like 376 * Font 1 & Font 2 (TrueType) 377 * or sometimes even : 378 * Font 1 & Font 2 & Font 3 (TrueType) 379 * Also if a Font has a name for this locale that name also 380 * exists in the registry using the appropriate platform encoding. 381 * What do we do then? 382 * 383 * Note: OpenType fonts seems to have " (TrueType)" suffix on Vista 384 * but " (OpenType)" on XP. 385 */ 386 static BOOL RegistryToBaseTTNameW(LPWSTR name) { 387 static const wchar_t TTSUFFIX[] = L" (TrueType)"; 388 static const wchar_t OTSUFFIX[] = L" (OpenType)"; 389 size_t TTSLEN = wcslen(TTSUFFIX); 390 wchar_t *suffix; 391 392 size_t len = wcslen(name); 393 if (len == 0) { 394 return FALSE; 395 } 396 if (name[len-1] != L')') { 397 return FALSE; 398 } 399 if (len <= TTSLEN) { 400 return FALSE; 401 } 402 /* suffix length is the same for truetype and opentype fonts */ 403 suffix = name + (len - TTSLEN); 404 if (wcscmp(suffix, TTSUFFIX) == 0 || wcscmp(suffix, OTSUFFIX) == 0) { 405 suffix[0] = L'\0'; /* truncate name */ 406 return TRUE; 407 } 408 return FALSE; 409 } 410 411 static void registerFontW(GdiFontMapInfo *fmi, jobject fontToFileMap, 412 LPWSTR name, LPWSTR data) { 413 414 wchar_t *ptr1, *ptr2; 415 jstring fontStr; 416 jstring fontStrLC; 417 JNIEnv *env = fmi->env; 418 size_t dslen = wcslen(data); 419 jstring fileStr = (*env)->NewString(env, data, (jsize)dslen); 420 if (fileStr == NULL) { 421 (*env)->ExceptionClear(env); 422 return; 423 } 424 425 /* TTC or ttc means it may be a collection. Need to parse out 426 * multiple font face names separated by " & " 427 * By only doing this for fonts which look like collections based on 428 * file name we are adhering to MS recommendations for font file names 429 * so it seems that we can be sure that this identifies precisely 430 * the MS-supplied truetype collections. 431 * This avoids any potential issues if a TTF file happens to have 432 * a & in the font name (I can't find anything which prohibits this) 433 * and also means we only parse the key in cases we know to be 434 * worthwhile. 435 */ 436 437 if ((data[dslen-1] == L'C' || data[dslen-1] == L'c') && 438 (ptr1 = wcsstr(name, L" & ")) != NULL) { 439 ptr1+=3; 440 while (ptr1 >= name) { /* marginally safer than while (true) */ 441 while ((ptr2 = wcsstr(ptr1, L" & ")) != NULL) { 442 ptr1 = ptr2+3; 443 } 444 fontStr = (*env)->NewString(env, ptr1, (jsize)wcslen(ptr1)); 445 if (fontStr == NULL) { 446 (*env)->ExceptionClear(env); 447 /* Delete the created reference before return */ 448 DeleteLocalReference(env, fileStr); 449 return; 450 } 451 452 fontStrLC = (*env)->CallObjectMethod(env, fontStr, 453 fmi->toLowerCaseMID, 454 fmi->locale); 455 /* Delete the created reference after its usage */ 456 DeleteLocalReference(env, fontStr); 457 if ((*env)->ExceptionCheck(env)) { 458 /* Delete the created reference before return */ 459 DeleteLocalReference(env, fileStr); 460 return; 461 } 462 463 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 464 fontStrLC, fileStr); 465 /* Delete the reference after its usage */ 466 DeleteLocalReference(env, fontStrLC); 467 if ((*env)->ExceptionCheck(env)) { 468 /* Delete the created reference before return */ 469 DeleteLocalReference(env, fileStr); 470 return; 471 } 472 473 if (ptr1 == name) { 474 break; 475 } else { 476 *(ptr1-3) = L'\0'; 477 ptr1 = name; 478 } 479 } 480 } else { 481 fontStr = (*env)->NewString(env, name, (jsize)wcslen(name)); 482 if (fontStr == NULL) { 483 (*env)->ExceptionClear(env); 484 /* Delete the created reference before return */ 485 DeleteLocalReference(env, fileStr); 486 return; 487 } 488 489 fontStrLC = (*env)->CallObjectMethod(env, fontStr, 490 fmi->toLowerCaseMID, fmi->locale); 491 /* Delete the created reference after its usage */ 492 DeleteLocalReference(env, fontStr); 493 if ((*env)->ExceptionCheck(env)) { 494 /* Delete the created reference before return */ 495 DeleteLocalReference(env, fileStr); 496 return; 497 } 498 499 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 500 fontStrLC, fileStr); 501 /* Delete the created reference after its usage */ 502 DeleteLocalReference(env, fontStrLC); 503 if ((*env)->ExceptionCheck(env)) { 504 /* Delete the created reference before return */ 505 DeleteLocalReference(env, fileStr); 506 return; 507 } 508 } 509 510 /* Delete the created reference after its usage */ 511 DeleteLocalReference(env, fileStr); 512 } 513 514 static void populateFontFileNameFromRegistryKey(HKEY regKey, GdiFontMapInfo *fmi, jobject fontToFileMap) 515 { 516 #define MAX_BUFFER (FILENAME_MAX+1) 517 const wchar_t wname[MAX_BUFFER]; 518 const char data[MAX_BUFFER]; 519 520 DWORD type; 521 LONG ret; 522 HKEY hkeyFonts; 523 DWORD dwNameSize; 524 DWORD dwDataValueSize; 525 DWORD nval; 526 DWORD dwNumValues, dwMaxValueNameLen, dwMaxValueDataLen; 527 528 /* Use the windows registry to map font names to files */ 529 ret = RegOpenKeyEx(regKey, 530 FONTKEY_NT, 0L, KEY_READ, &hkeyFonts); 531 if (ret != ERROR_SUCCESS) { 532 return; 533 } 534 535 ret = RegQueryInfoKeyW(hkeyFonts, NULL, NULL, NULL, NULL, NULL, NULL, 536 &dwNumValues, &dwMaxValueNameLen, 537 &dwMaxValueDataLen, NULL, NULL); 538 539 if (ret != ERROR_SUCCESS || 540 dwMaxValueNameLen >= MAX_BUFFER || 541 dwMaxValueDataLen >= MAX_BUFFER) { 542 RegCloseKey(hkeyFonts); 543 return; 544 } 545 for (nval = 0; nval < dwNumValues; nval++ ) { 546 dwNameSize = MAX_BUFFER; 547 dwDataValueSize = MAX_BUFFER; 548 ret = RegEnumValueW(hkeyFonts, nval, (LPWSTR)wname, &dwNameSize, 549 NULL, &type, (LPBYTE)data, &dwDataValueSize); 550 551 if (ret != ERROR_SUCCESS) { 552 break; 553 } 554 if (type != REG_SZ) { /* REG_SZ means a null-terminated string */ 555 continue; 556 } 557 558 if (!RegistryToBaseTTNameW((LPWSTR)wname) ) { 559 /* If the filename ends with ".ttf" or ".otf" also accept it. 560 * Not expecting to need to do this for .ttc files. 561 * Also note this code is not mirrored in the "A" (win9x) path. 562 */ 563 LPWSTR dot = wcsrchr((LPWSTR)data, L'.'); 564 if (dot == NULL || ((wcsicmp(dot, L".ttf") != 0) 565 && (wcsicmp(dot, L".otf") != 0))) { 566 continue; /* not a TT font... */ 567 } 568 } 569 registerFontW(fmi, fontToFileMap, (LPWSTR)wname, (LPWSTR)data); 570 } 571 572 RegCloseKey(hkeyFonts); 573 } 574 575 /* Obtain all the fontname -> filename mappings. 576 * This is called once and the results returned to Java code which can 577 * use it for lookups to reduce or avoid the need to search font files. 578 */ 579 JNIEXPORT void JNICALL 580 Java_sun_awt_Win32FontManager_populateFontFileNameMap0 581 (JNIEnv *env, jclass obj, jobject fontToFileMap, 582 jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale) 583 { 584 jclass classIDHashMap; 585 jclass classIDString; 586 jmethodID putMID; 587 GdiFontMapInfo fmi; 588 LOGFONTW lfw; 589 590 /* Check we were passed all the maps we need, and do lookup of 591 * methods for JNI up-calls 592 */ 593 if (fontToFileMap == NULL || 594 fontToFamilyMap == NULL || 595 familyToFontListMap == NULL) { 596 return; 597 } 598 classIDHashMap = (*env)->FindClass(env, "java/util/HashMap"); 599 if (classIDHashMap == NULL) { 600 return; 601 } 602 putMID = (*env)->GetMethodID(env, classIDHashMap, "put", 603 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 604 if (putMID == NULL) { 605 return; 606 } 607 608 fmi.env = env; 609 fmi.fontToFamilyMap = fontToFamilyMap; 610 fmi.familyToFontListMap = familyToFontListMap; 611 fmi.putMID = putMID; 612 fmi.locale = locale; 613 fmi.containsKeyMID = (*env)->GetMethodID(env, classIDHashMap, 614 "containsKey", 615 "(Ljava/lang/Object;)Z"); 616 if (fmi.containsKeyMID == NULL) { 617 return; 618 } 619 620 fmi.arrayListClass = (*env)->FindClass(env, "java/util/ArrayList"); 621 if (fmi.arrayListClass == NULL) { 622 return; 623 } 624 fmi.arrayListCtr = (*env)->GetMethodID(env, fmi.arrayListClass, 625 "<init>", "(I)V"); 626 if (fmi.arrayListCtr == NULL) { 627 return; 628 } 629 fmi.addMID = (*env)->GetMethodID(env, fmi.arrayListClass, 630 "add", "(Ljava/lang/Object;)Z"); 631 if (fmi.addMID == NULL) { 632 return; 633 } 634 635 classIDString = (*env)->FindClass(env, "java/lang/String"); 636 if (classIDString == NULL) { 637 return; 638 } 639 fmi.toLowerCaseMID = 640 (*env)->GetMethodID(env, classIDString, "toLowerCase", 641 "(Ljava/util/Locale;)Ljava/lang/String;"); 642 if (fmi.toLowerCaseMID == NULL) { 643 return; 644 } 645 646 screenDC = GetDC(NULL); 647 if (screenDC == NULL) { 648 return; 649 } 650 651 /* Enumerate fonts via GDI to build maps of fonts and families */ 652 memset(&lfw, 0, sizeof(lfw)); 653 lfw.lfCharSet = DEFAULT_CHARSET; /* all charsets */ 654 wcscpy(lfw.lfFaceName, L""); /* one face per family (CHECK) */ 655 EnumFontFamiliesExW(screenDC, &lfw, 656 (FONTENUMPROCW)EnumFamilyNamesW, 657 (LPARAM)(&fmi), 0L); 658 659 /* Starting from Windows 10 Preview Build 17704, when a user installs non-system fonts, 660 * then by default they are installed in a new per-user location as specified in a 661 * per user registry entry. 662 */ 663 populateFontFileNameFromRegistryKey(HKEY_CURRENT_USER, &fmi, fontToFileMap); 664 populateFontFileNameFromRegistryKey(HKEY_LOCAL_MACHINE, &fmi, fontToFileMap); 665 666 ReleaseDC(NULL, screenDC); 667 screenDC = NULL; 668 }