1 /* 2 * Copyright (c) 1998, 2013, 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 36 JNIEXPORT jstring JNICALL Java_sun_awt_Win32FontManager_getFontPath(JNIEnv *env, jobject thiz, jboolean noType1) 37 { 38 char windir[BSIZE]; 39 char sysdir[BSIZE]; 40 char fontpath[BSIZE*2]; 41 char *end; 42 43 /* Locate fonts directories relative to the Windows System directory. 44 * If Windows System location is different than the user's window 45 * directory location, as in a shared Windows installation, 46 * return both locations as potential font directories 47 */ 48 GetSystemDirectory(sysdir, BSIZE); 49 end = strrchr(sysdir,'\\'); 50 if (end && (stricmp(end,"\\System") || stricmp(end,"\\System32"))) { 51 *end = 0; 52 strcat(sysdir, "\\Fonts"); 53 } 54 55 GetWindowsDirectory(windir, BSIZE); 56 if (strlen(windir) > BSIZE-7) { 57 *windir = 0; 58 } else { 59 strcat(windir, "\\Fonts"); 60 } 61 62 strcpy(fontpath,sysdir); 63 if (stricmp(sysdir,windir)) { 64 strcat(fontpath,";"); 65 strcat(fontpath,windir); 66 } 67 68 return JNU_NewStringPlatform(env, fontpath); 69 } 70 71 /* The code below is used to obtain information from the windows font APIS 72 * and registry on which fonts are available and what font files hold those 73 * fonts. The results are used to speed font lookup. 74 */ 75 76 typedef struct GdiFontMapInfo { 77 JNIEnv *env; 78 jstring family; 79 jobject fontToFamilyMap; 80 jobject familyToFontListMap; 81 jobject list; 82 jmethodID putMID; 83 jmethodID containsKeyMID; 84 jclass arrayListClass; 85 jmethodID arrayListCtr; 86 jmethodID addMID; 87 jmethodID toLowerCaseMID; 88 jobject locale; 89 } GdiFontMapInfo; 90 91 /* IS_NT means NT or later OSes which support Unicode. 92 * We have to painfully deal with the ASCII and non-ASCII case we 93 * we really want to get the font names as unicode wherever possible. 94 * UNICODE_OS is 0 to mean uninitialised, 1 to mean not a unicode OS, 95 * 2 to mean a unicode OS. 96 */ 97 98 #define UC_UNKNOWN 0 99 #define UC_NO 1 100 #define UC_YES 2 101 static int UNICODE_OS = UC_UNKNOWN; 102 static int GetOSVersion () { 103 OSVERSIONINFO vinfo; 104 vinfo.dwOSVersionInfoSize = sizeof(vinfo); 105 GetVersionEx(&vinfo); 106 if ((int)vinfo.dwMajorVersion > 4) { 107 UNICODE_OS = UC_YES; 108 } else if ((int)vinfo.dwMajorVersion < 4) { 109 UNICODE_OS = UC_NO; 110 } else { 111 if ((int)vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { 112 UNICODE_OS = UC_NO; 113 } else { 114 UNICODE_OS = UC_YES; 115 } 116 } 117 return UNICODE_OS; 118 } 119 120 #define IS_NT ((UNICODE_OS == UC_UNKNOWN) \ 121 ? (GetOSVersion() == UC_YES) : (UNICODE_OS == UC_YES)) 122 123 /* NT is W2K & XP. WIN is Win9x */ 124 static const char FONTKEY_NT[] = 125 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; 126 static const char FONTKEY_WIN[] = 127 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts"; 128 129 /* Callback for call to EnumFontFamiliesEx in the EnumFamilyNames function. 130 * Expects to be called once for each face name in the family specified 131 * in the call. We extract the full name for the font which is expected 132 * to be in the "system encoding" and create canonical and lower case 133 * Java strings for the name which are added to the maps. The lower case 134 * name is used as key to the family name value in the font to family map, 135 * the canonical name is one of the"list" of members of the family. 136 */ 137 static int CALLBACK EnumFontFacesInFamilyProcA( 138 ENUMLOGFONTEXA *lpelfe, 139 NEWTEXTMETRICEX *lpntme, 140 int FontType, 141 LPARAM lParam ) 142 { 143 GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; 144 JNIEnv *env = fmi->env; 145 jstring fullname, fullnameLC; 146 147 /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ 148 if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { 149 return 1; 150 } 151 152 /* printf("FULL=%s\n",lpelfe->elfFullName);fflush(stdout); */ 153 154 fullname = JNU_NewStringPlatform(env, lpelfe->elfFullName); 155 if (fullname == NULL) { 156 (*env)->ExceptionClear(env); 157 return 1; 158 } 159 fullnameLC = (*env)->CallObjectMethod(env, fullname, 160 fmi->toLowerCaseMID, fmi->locale); 161 (*env)->CallBooleanMethod(env, fmi->list, fmi->addMID, fullname); 162 (*env)->CallObjectMethod(env, fmi->fontToFamilyMap, 163 fmi->putMID, fullnameLC, fmi->family); 164 return 1; 165 } 166 167 typedef struct CheckFamilyInfo { 168 wchar_t *family; 169 wchar_t* fullName; 170 int isDifferent; 171 } CheckFamilyInfo; 172 173 static int CALLBACK CheckFontFamilyProcW( 174 ENUMLOGFONTEXW *lpelfe, 175 NEWTEXTMETRICEX *lpntme, 176 int FontType, 177 LPARAM lParam) 178 { 179 CheckFamilyInfo *info = (CheckFamilyInfo*)lParam; 180 info->isDifferent = wcscmp(lpelfe->elfLogFont.lfFaceName, info->family); 181 182 /* if (!info->isDifferent) { */ 183 /* wprintf(LFor font %s expected family=%s instead got %s\n", */ 184 /* lpelfe->elfFullName, */ 185 /* info->family, */ 186 /* lpelfe->elfLogFont.lfFaceName); */ 187 /* fflush(stdout); */ 188 /* } */ 189 return 0; 190 } 191 192 /* This HDC is initialised and released in the populate family map 193 * JNI entry point, and used within the call which would otherwise 194 * create many DCs. 195 */ 196 static HDC screenDC = NULL; 197 198 static int DifferentFamily(wchar_t *family, wchar_t* fullName) { 199 LOGFONTW lfw; 200 CheckFamilyInfo info; 201 202 /* If fullName can't be stored in the struct, assume correct family */ 203 if (wcslen((LPWSTR)fullName) >= LF_FACESIZE) { 204 return 0; 205 } 206 207 memset(&info, 0, sizeof(CheckFamilyInfo)); 208 info.family = family; 209 info.fullName = fullName; 210 info.isDifferent = 0; 211 212 memset(&lfw, 0, sizeof(lfw)); 213 wcscpy(lfw.lfFaceName, fullName); 214 lfw.lfCharSet = DEFAULT_CHARSET; 215 EnumFontFamiliesExW(screenDC, &lfw, 216 (FONTENUMPROCW)CheckFontFamilyProcW, 217 (LPARAM)(&info), 0L); 218 219 return info.isDifferent; 220 } 221 222 static int CALLBACK EnumFontFacesInFamilyProcW( 223 ENUMLOGFONTEXW *lpelfe, 224 NEWTEXTMETRICEX *lpntme, 225 int FontType, 226 LPARAM lParam) 227 { 228 GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; 229 JNIEnv *env = fmi->env; 230 jstring fullname, fullnameLC; 231 232 /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ 233 if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { 234 return 1; 235 } 236 237 /* Windows has font aliases and so may enumerate fonts from 238 * the aliased family if any actual font of that family is installed. 239 * To protect against it ignore fonts which aren't enumerated under 240 * their true family. 241 */ 242 if (DifferentFamily(lpelfe->elfLogFont.lfFaceName, 243 lpelfe->elfFullName)) { 244 return 1; 245 } 246 247 fullname = (*env)->NewString(env, lpelfe->elfFullName, 248 (jsize)wcslen((LPWSTR)lpelfe->elfFullName)); 249 if (fullname == NULL) { 250 (*env)->ExceptionClear(env); 251 return 1; 252 } 253 fullnameLC = (*env)->CallObjectMethod(env, fullname, 254 fmi->toLowerCaseMID, fmi->locale); 255 (*env)->CallBooleanMethod(env, fmi->list, fmi->addMID, fullname); 256 (*env)->CallObjectMethod(env, fmi->fontToFamilyMap, 257 fmi->putMID, fullnameLC, fmi->family); 258 return 1; 259 } 260 261 /* Callback for EnumFontFamiliesEx in populateFontFileNameMap. 262 * Expects to be called for every charset of every font family. 263 * If this is the first time we have been called for this family, 264 * add a new mapping to the familyToFontListMap from this family to a 265 * list of its members. To populate that list, further enumerate all faces 266 * in this family for the matched charset. This assumes that all fonts 267 * in a family support the same charset, which is a fairly safe assumption 268 * and saves time as the call we make here to EnumFontFamiliesEx will 269 * enumerate the members of this family just once each. 270 * Because we set fmi->list to be the newly created list the call back 271 * can safely add to that list without a search. 272 */ 273 static int CALLBACK EnumFamilyNamesA( 274 ENUMLOGFONTEXA *lpelfe, /* pointer to logical-font data */ 275 NEWTEXTMETRICEX *lpntme, /* pointer to physical-font data */ 276 int FontType, /* type of font */ 277 LPARAM lParam) /* application-defined data */ 278 { 279 GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; 280 JNIEnv *env = fmi->env; 281 jstring familyLC; 282 LOGFONTA lfa; 283 284 /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ 285 if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { 286 return 1; 287 } 288 289 /* Windows lists fonts which have a vmtx (vertical metrics) table twice. 290 * Once using their normal name, and again preceded by '@'. These appear 291 * in font lists in some windows apps, such as wordpad. We don't want 292 * these so we skip any font where the first character is '@' 293 */ 294 if (lpelfe->elfLogFont.lfFaceName[0] == '@') { 295 return 1; 296 } 297 fmi->family = JNU_NewStringPlatform(env,lpelfe->elfLogFont.lfFaceName); 298 if (fmi->family == NULL) { 299 (*env)->ExceptionClear(env); 300 return 1; 301 } 302 familyLC = (*env)->CallObjectMethod(env, fmi->family, 303 fmi->toLowerCaseMID, fmi->locale); 304 /* check if already seen this family with a different charset */ 305 if ((*env)->CallBooleanMethod(env,fmi->familyToFontListMap, 306 fmi->containsKeyMID, familyLC)) { 307 return 1; 308 } 309 fmi->list = (*env)->NewObject(env, 310 fmi->arrayListClass, fmi->arrayListCtr, 4); 311 if (fmi->list == NULL) { 312 (*env)->ExceptionClear(env); 313 return 1; 314 } 315 (*env)->CallObjectMethod(env, fmi->familyToFontListMap, 316 fmi->putMID, familyLC, fmi->list); 317 318 /* printf("FAMILY=%s\n", lpelfe->elfLogFont.lfFaceName);fflush(stdout); */ 319 320 memset(&lfa, 0, sizeof(lfa)); 321 strcpy(lfa.lfFaceName, lpelfe->elfLogFont.lfFaceName); 322 lfa.lfCharSet = lpelfe->elfLogFont.lfCharSet; 323 EnumFontFamiliesExA(screenDC, &lfa, 324 (FONTENUMPROCA)EnumFontFacesInFamilyProcA, 325 lParam, 0L); 326 return 1; 327 } 328 329 static int CALLBACK EnumFamilyNamesW( 330 ENUMLOGFONTEXW *lpelfe, /* pointer to logical-font data */ 331 NEWTEXTMETRICEX *lpntme, /* pointer to physical-font data */ 332 int FontType, /* type of font */ 333 LPARAM lParam ) /* application-defined data */ 334 { 335 GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; 336 JNIEnv *env = fmi->env; 337 jstring familyLC; 338 size_t slen; 339 LOGFONTW lfw; 340 341 /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ 342 if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { 343 return 1; 344 } 345 /* wprintf(L"FAMILY=%s charset=%d FULL=%s\n", */ 346 /* lpelfe->elfLogFont.lfFaceName, */ 347 /* lpelfe->elfLogFont.lfCharSet, */ 348 /* lpelfe->elfFullName); */ 349 /* fflush(stdout); */ 350 351 /* Windows lists fonts which have a vmtx (vertical metrics) table twice. 352 * Once using their normal name, and again preceded by '@'. These appear 353 * in font lists in some windows apps, such as wordpad. We don't want 354 * these so we skip any font where the first character is '@' 355 */ 356 if (lpelfe->elfLogFont.lfFaceName[0] == L'@') { 357 return 1; 358 } 359 slen = wcslen(lpelfe->elfLogFont.lfFaceName); 360 fmi->family = (*env)->NewString(env,lpelfe->elfLogFont.lfFaceName, (jsize)slen); 361 if (fmi->family == NULL) { 362 (*env)->ExceptionClear(env); 363 return 1; 364 } 365 familyLC = (*env)->CallObjectMethod(env, fmi->family, 366 fmi->toLowerCaseMID, fmi->locale); 367 /* check if already seen this family with a different charset */ 368 if ((*env)->CallBooleanMethod(env,fmi->familyToFontListMap, 369 fmi->containsKeyMID, familyLC)) { 370 return 1; 371 } 372 fmi->list = (*env)->NewObject(env, 373 fmi->arrayListClass, fmi->arrayListCtr, 4); 374 if (fmi->list == NULL) { 375 (*env)->ExceptionClear(env); 376 return 1; 377 } 378 (*env)->CallObjectMethod(env, fmi->familyToFontListMap, 379 fmi->putMID, familyLC, fmi->list); 380 381 memset(&lfw, 0, sizeof(lfw)); 382 wcscpy(lfw.lfFaceName, lpelfe->elfLogFont.lfFaceName); 383 lfw.lfCharSet = lpelfe->elfLogFont.lfCharSet; 384 EnumFontFamiliesExW(screenDC, &lfw, 385 (FONTENUMPROCW)EnumFontFacesInFamilyProcW, 386 lParam, 0L); 387 return 1; 388 } 389 390 391 /* It looks like TrueType fonts have " (TrueType)" tacked on the end of their 392 * name, so we can try to use that to distinguish TT from other fonts. 393 * However if a program "installed" a font in the registry the key may 394 * not include that. We could also try to "pass" fonts which have no "(..)" 395 * at the end. But that turns out to pass a few .FON files that MS supply. 396 * If there's no parenthesized type string, we could next try to infer 397 * the file type from the file name extension. Since the MS entries that 398 * have no type string are very few, and have odd names like "MS-DOS CP 437" 399 * and would never return a Java Font anyway its currently OK to put these 400 * in the font map, although clearly the returned names must never percolate 401 * up into a list of available fonts returned to the application. 402 * Additionally for TTC font files the key looks like 403 * Font 1 & Font 2 (TrueType) 404 * or sometimes even : 405 * Font 1 & Font 2 & Font 3 (TrueType) 406 * Also if a Font has a name for this locale that name also 407 * exists in the registry using the appropriate platform encoding. 408 * What do we do then? 409 * 410 * Note: OpenType fonts seems to have " (TrueType)" suffix on Vista 411 * but " (OpenType)" on XP. 412 */ 413 414 static BOOL RegistryToBaseTTNameA(LPSTR name) { 415 static const char TTSUFFIX[] = " (TrueType)"; 416 static const char OTSUFFIX[] = " (OpenType)"; 417 size_t TTSLEN = strlen(TTSUFFIX); 418 char *suffix; 419 420 size_t len = strlen(name); 421 if (len == 0) { 422 return FALSE; 423 } 424 if (name[len-1] != ')') { 425 return FALSE; 426 } 427 if (len <= TTSLEN) { 428 return FALSE; 429 } 430 431 /* suffix length is the same for truetype and opentype fonts */ 432 suffix = name + len - TTSLEN; 433 if (strcmp(suffix, TTSUFFIX) == 0 || strcmp(suffix, OTSUFFIX) == 0) { 434 suffix[0] = '\0'; /* truncate name */ 435 return TRUE; 436 } 437 return FALSE; 438 } 439 440 static BOOL RegistryToBaseTTNameW(LPWSTR name) { 441 static const wchar_t TTSUFFIX[] = L" (TrueType)"; 442 static const wchar_t OTSUFFIX[] = L" (OpenType)"; 443 size_t TTSLEN = wcslen(TTSUFFIX); 444 wchar_t *suffix; 445 446 size_t len = wcslen(name); 447 if (len == 0) { 448 return FALSE; 449 } 450 if (name[len-1] != L')') { 451 return FALSE; 452 } 453 if (len <= TTSLEN) { 454 return FALSE; 455 } 456 /* suffix length is the same for truetype and opentype fonts */ 457 suffix = name + (len - TTSLEN); 458 if (wcscmp(suffix, TTSUFFIX) == 0 || wcscmp(suffix, OTSUFFIX) == 0) { 459 suffix[0] = L'\0'; /* truncate name */ 460 return TRUE; 461 } 462 return FALSE; 463 } 464 465 static void registerFontA(GdiFontMapInfo *fmi, jobject fontToFileMap, 466 LPCSTR name, LPCSTR data) { 467 LPSTR ptr1, ptr2; 468 jstring fontStr; 469 JNIEnv *env = fmi->env; 470 size_t dslen = strlen(data); 471 jstring fileStr = JNU_NewStringPlatform(env, data); 472 if (fileStr == NULL) { 473 (*env)->ExceptionClear(env); 474 return; 475 } 476 477 /* TTC or ttc means it may be a collection. Need to parse out 478 * multiple font face names separated by " & " 479 * By only doing this for fonts which look like collections based on 480 * file name we are adhering to MS recommendations for font file names 481 * so it seems that we can be sure that this identifies precisely 482 * the MS-supplied truetype collections. 483 * This avoids any potential issues if a TTF file happens to have 484 * a & in the font name (I can't find anything which prohibits this) 485 * and also means we only parse the key in cases we know to be 486 * worthwhile. 487 */ 488 if ((data[dslen-1] == 'C' || data[dslen-1] == 'c') && 489 (ptr1 = strstr(name, " & ")) != NULL) { 490 ptr1+=3; 491 while (ptr1 >= name) { /* marginally safer than while (true) */ 492 while ((ptr2 = strstr(ptr1, " & ")) != NULL) { 493 ptr1 = ptr2+3; 494 } 495 fontStr = JNU_NewStringPlatform(env, ptr1); 496 if (fontStr == NULL) { 497 (*env)->ExceptionClear(env); 498 return; 499 } 500 fontStr = (*env)->CallObjectMethod(env, fontStr, 501 fmi->toLowerCaseMID, 502 fmi->locale); 503 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 504 fontStr, fileStr); 505 if (ptr1 == name) { 506 break; 507 } else { 508 *(ptr1-3) ='\0'; 509 ptr1 = (LPSTR)name; 510 } 511 } 512 } else { 513 fontStr = JNU_NewStringPlatform(env, name); 514 if (fontStr == NULL) { 515 (*env)->ExceptionClear(env); 516 return; 517 } 518 fontStr = (*env)->CallObjectMethod(env, fontStr, 519 fmi->toLowerCaseMID, fmi->locale); 520 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 521 fontStr, fileStr); 522 } 523 } 524 525 static void registerFontW(GdiFontMapInfo *fmi, jobject fontToFileMap, 526 LPWSTR name, LPWSTR data) { 527 528 wchar_t *ptr1, *ptr2; 529 jstring fontStr; 530 JNIEnv *env = fmi->env; 531 size_t dslen = wcslen(data); 532 jstring fileStr = (*env)->NewString(env, data, (jsize)dslen); 533 if (fileStr == NULL) { 534 (*env)->ExceptionClear(env); 535 return; 536 } 537 538 /* TTC or ttc means it may be a collection. Need to parse out 539 * multiple font face names separated by " & " 540 * By only doing this for fonts which look like collections based on 541 * file name we are adhering to MS recommendations for font file names 542 * so it seems that we can be sure that this identifies precisely 543 * the MS-supplied truetype collections. 544 * This avoids any potential issues if a TTF file happens to have 545 * a & in the font name (I can't find anything which prohibits this) 546 * and also means we only parse the key in cases we know to be 547 * worthwhile. 548 */ 549 550 if ((data[dslen-1] == L'C' || data[dslen-1] == L'c') && 551 (ptr1 = wcsstr(name, L" & ")) != NULL) { 552 ptr1+=3; 553 while (ptr1 >= name) { /* marginally safer than while (true) */ 554 while ((ptr2 = wcsstr(ptr1, L" & ")) != NULL) { 555 ptr1 = ptr2+3; 556 } 557 fontStr = (*env)->NewString(env, ptr1, (jsize)wcslen(ptr1)); 558 if (fontStr == NULL) { 559 (*env)->ExceptionClear(env); 560 return; 561 } 562 fontStr = (*env)->CallObjectMethod(env, fontStr, 563 fmi->toLowerCaseMID, 564 fmi->locale); 565 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 566 fontStr, fileStr); 567 if (ptr1 == name) { 568 break; 569 } else { 570 *(ptr1-3) = L'\0'; 571 ptr1 = name; 572 } 573 } 574 } else { 575 fontStr = (*env)->NewString(env, name, (jsize)wcslen(name)); 576 if (fontStr == NULL) { 577 (*env)->ExceptionClear(env); 578 return; 579 } 580 fontStr = (*env)->CallObjectMethod(env, fontStr, 581 fmi->toLowerCaseMID, fmi->locale); 582 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 583 fontStr, fileStr); 584 } 585 } 586 587 /* Obtain all the fontname -> filename mappings. 588 * This is called once and the results returned to Java code which can 589 * use it for lookups to reduce or avoid the need to search font files. 590 */ 591 JNIEXPORT void JNICALL 592 Java_sun_awt_Win32FontManager_populateFontFileNameMap0 593 (JNIEnv *env, jclass obj, jobject fontToFileMap, 594 jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale) 595 { 596 #define MAX_BUFFER (FILENAME_MAX+1) 597 const wchar_t wname[MAX_BUFFER]; 598 const char cname[MAX_BUFFER]; 599 const char data[MAX_BUFFER]; 600 601 DWORD type; 602 LONG ret; 603 HKEY hkeyFonts; 604 DWORD dwNameSize; 605 DWORD dwDataValueSize; 606 DWORD nval; 607 LPCSTR fontKeyName; 608 DWORD dwNumValues, dwMaxValueNameLen, dwMaxValueDataLen; 609 DWORD numValues = 0; 610 jclass classID; 611 jmethodID putMID; 612 GdiFontMapInfo fmi; 613 614 /* Check we were passed all the maps we need, and do lookup of 615 * methods for JNI up-calls 616 */ 617 if (fontToFileMap == NULL || 618 fontToFamilyMap == NULL || 619 familyToFontListMap == NULL) { 620 return; 621 } 622 classID = (*env)->FindClass(env, "java/util/HashMap"); 623 if (classID == NULL) { 624 return; 625 } 626 putMID = (*env)->GetMethodID(env, classID, "put", 627 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 628 if (putMID == NULL) { 629 return; 630 } 631 632 fmi.env = env; 633 fmi.fontToFamilyMap = fontToFamilyMap; 634 fmi.familyToFontListMap = familyToFontListMap; 635 fmi.putMID = putMID; 636 fmi.locale = locale; 637 fmi.containsKeyMID = (*env)->GetMethodID(env, classID, "containsKey", 638 "(Ljava/lang/Object;)Z"); 639 if (fmi.containsKeyMID == NULL) { 640 return; 641 } 642 643 fmi.arrayListClass = (*env)->FindClass(env, "java/util/ArrayList"); 644 if (fmi.arrayListClass == NULL) { 645 return; 646 } 647 fmi.arrayListCtr = (*env)->GetMethodID(env, fmi.arrayListClass, 648 "<init>", "(I)V"); 649 if (fmi.arrayListCtr == NULL) { 650 return; 651 } 652 fmi.addMID = (*env)->GetMethodID(env, fmi.arrayListClass, 653 "add", "(Ljava/lang/Object;)Z"); 654 if (fmi.addMID == NULL) { 655 return; 656 } 657 classID = (*env)->FindClass(env, "java/lang/String"); 658 if (classID == NULL) { 659 return; 660 } 661 fmi.toLowerCaseMID = 662 (*env)->GetMethodID(env, classID, "toLowerCase", 663 "(Ljava/util/Locale;)Ljava/lang/String;"); 664 if (fmi.toLowerCaseMID == NULL) { 665 return; 666 } 667 668 screenDC = GetDC(NULL); 669 if (screenDC == NULL) { 670 return; 671 } 672 /* Enumerate fonts via GDI to build maps of fonts and families */ 673 if (IS_NT) { 674 LOGFONTW lfw; 675 memset(&lfw, 0, sizeof(lfw)); 676 lfw.lfCharSet = DEFAULT_CHARSET; /* all charsets */ 677 wcscpy(lfw.lfFaceName, L""); /* one face per family (CHECK) */ 678 EnumFontFamiliesExW(screenDC, &lfw, 679 (FONTENUMPROCW)EnumFamilyNamesW, 680 (LPARAM)(&fmi), 0L); 681 } else { 682 LOGFONT lfa; 683 memset(&lfa, 0, sizeof(lfa)); 684 lfa.lfCharSet = DEFAULT_CHARSET; /* all charsets */ 685 strcpy(lfa.lfFaceName, ""); /* one face per family */ 686 ret = EnumFontFamiliesExA(screenDC, &lfa, 687 (FONTENUMPROCA)EnumFamilyNamesA, 688 (LPARAM)(&fmi), 0L); 689 } 690 691 /* Use the windows registry to map font names to files */ 692 fontKeyName = (IS_NT) ? FONTKEY_NT : FONTKEY_WIN; 693 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 694 fontKeyName, 0L, KEY_READ, &hkeyFonts); 695 if (ret != ERROR_SUCCESS) { 696 ReleaseDC(NULL, screenDC); 697 screenDC = NULL; 698 return; 699 } 700 701 if (IS_NT) { 702 ret = RegQueryInfoKeyW(hkeyFonts, NULL, NULL, NULL, NULL, NULL, NULL, 703 &dwNumValues, &dwMaxValueNameLen, 704 &dwMaxValueDataLen, NULL, NULL); 705 } else { 706 ret = RegQueryInfoKeyA(hkeyFonts, NULL, NULL, NULL, NULL, NULL, NULL, 707 &dwNumValues, &dwMaxValueNameLen, 708 &dwMaxValueDataLen, NULL, NULL); 709 } 710 if (ret != ERROR_SUCCESS || 711 dwMaxValueNameLen >= MAX_BUFFER || 712 dwMaxValueDataLen >= MAX_BUFFER) { 713 RegCloseKey(hkeyFonts); 714 ReleaseDC(NULL, screenDC); 715 screenDC = NULL; 716 return; 717 } 718 for (nval = 0; nval < dwNumValues; nval++ ) { 719 dwNameSize = MAX_BUFFER; 720 dwDataValueSize = MAX_BUFFER; 721 if (IS_NT) { 722 ret = RegEnumValueW(hkeyFonts, nval, (LPWSTR)wname, &dwNameSize, 723 NULL, &type, (LPBYTE)data, &dwDataValueSize); 724 } else { 725 ret = RegEnumValueA(hkeyFonts, nval, (LPSTR)cname, &dwNameSize, 726 NULL, &type, (LPBYTE)data, &dwDataValueSize); 727 } 728 if (ret != ERROR_SUCCESS) { 729 break; 730 } 731 if (type != REG_SZ) { /* REG_SZ means a null-terminated string */ 732 continue; 733 } 734 if (IS_NT) { 735 if (!RegistryToBaseTTNameW((LPWSTR)wname) ) { 736 /* If the filename ends with ".ttf" or ".otf" also accept it. 737 * Not expecting to need to do this for .ttc files. 738 * Also note this code is not mirrored in the "A" (win9x) path. 739 */ 740 LPWSTR dot = wcsrchr((LPWSTR)data, L'.'); 741 if (dot == NULL || ((wcsicmp(dot, L".ttf") != 0) 742 && (wcsicmp(dot, L".otf") != 0))) { 743 continue; /* not a TT font... */ 744 } 745 } 746 registerFontW(&fmi, fontToFileMap, (LPWSTR)wname, (LPWSTR)data); 747 } else { 748 if (!RegistryToBaseTTNameA((LPSTR)cname)) { 749 continue; /* not a TT font... */ 750 } 751 registerFontA(&fmi, fontToFileMap, cname, (LPCSTR)data); 752 } 753 } 754 RegCloseKey(hkeyFonts); 755 ReleaseDC(NULL, screenDC); 756 screenDC = NULL; 757 }