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