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 267 /* Exceptions indicate critical errors such that program cannot continue 268 * with further execution. Henceforth, the function returns immediately 269 * on pending exceptions. In these situations, the function also returns 270 * 0 indicating windows API to stop further enumeration and callbacks. 271 * 272 * The JNI functions do not clear the pending exceptions. This allows the 273 * caller (Java code) to check and handle exceptions in the best possible 274 * way. 275 */ 276 if ((*env)->ExceptionCheck(env)) { 277 return 0; 278 } 279 280 /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ 281 if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { 282 return 1; 283 } 284 /* wprintf(L"FAMILY=%s charset=%d FULL=%s\n", */ 285 /* lpelfe->elfLogFont.lfFaceName, */ 286 /* lpelfe->elfLogFont.lfCharSet, */ 287 /* lpelfe->elfFullName); */ 288 /* fflush(stdout); */ 289 290 /* Windows lists fonts which have a vmtx (vertical metrics) table twice. 291 * Once using their normal name, and again preceded by '@'. These appear 292 * in font lists in some windows apps, such as wordpad. We don't want 293 * these so we skip any font where the first character is '@' 294 */ 295 if (lpelfe->elfLogFont.lfFaceName[0] == L'@') { 296 return 1; 297 } 298 slen = wcslen(lpelfe->elfLogFont.lfFaceName); 299 fmi->family = (*env)->NewString(env,lpelfe->elfLogFont.lfFaceName, (jsize)slen); 300 if (fmi->family == NULL) { 301 (*env)->ExceptionClear(env); 302 return 1; 303 } 304 305 familyLC = (*env)->CallObjectMethod(env, fmi->family, 306 fmi->toLowerCaseMID, fmi->locale); 307 /* Delete the created reference after its usage */ 308 if ((*env)->ExceptionCheck(env)) { 309 DeleteLocalReference(env, fmi->family); 310 return 0; 311 } 312 313 /* check if already seen this family with a different charset */ 314 jboolean mapHasKey = (*env)->CallBooleanMethod(env, 315 fmi->familyToFontListMap, 316 fmi->containsKeyMID, 317 familyLC); 318 if ((*env)->ExceptionCheck(env)) { 319 /* Delete the created references before return */ 320 DeleteLocalReference(env, fmi->family); 321 DeleteLocalReference(env, familyLC); 322 return 0; 323 } else if (mapHasKey) { 324 /* Delete the created references before return */ 325 DeleteLocalReference(env, fmi->family); 326 DeleteLocalReference(env, familyLC); 327 return 1; 328 } 329 330 fmi->list = (*env)->NewObject(env, 331 fmi->arrayListClass, fmi->arrayListCtr, 4); 332 if (fmi->list == NULL) { 333 /* Delete the created references before return */ 334 DeleteLocalReference(env, fmi->family); 335 DeleteLocalReference(env, familyLC); 336 return 0; 337 } 338 339 (*env)->CallObjectMethod(env, fmi->familyToFontListMap, 340 fmi->putMID, familyLC, fmi->list); 341 /* Delete the created reference after its usage */ 342 DeleteLocalReference(env, familyLC); 343 if ((*env)->ExceptionCheck(env)) { 344 /* Delete the created reference before return */ 345 DeleteLocalReference(env, fmi->family); 346 DeleteLocalReference(env, fmi->list); 347 return 0; 348 } 349 350 memset(&lfw, 0, sizeof(lfw)); 351 wcscpy(lfw.lfFaceName, lpelfe->elfLogFont.lfFaceName); 352 lfw.lfCharSet = lpelfe->elfLogFont.lfCharSet; 353 EnumFontFamiliesExW(screenDC, &lfw, 354 (FONTENUMPROCW)EnumFontFacesInFamilyProcW, 355 lParam, 0L); 356 357 /* Delete the created reference after its usage in the enum function */ 358 DeleteLocalReference(env, fmi->family); 359 DeleteLocalReference(env, fmi->list); 360 return 1; 361 } 362 363 /* It looks like TrueType fonts have " (TrueType)" tacked on the end of their 364 * name, so we can try to use that to distinguish TT from other fonts. 365 * However if a program "installed" a font in the registry the key may 366 * not include that. We could also try to "pass" fonts which have no "(..)" 367 * at the end. But that turns out to pass a few .FON files that MS supply. 368 * If there's no parenthesized type string, we could next try to infer 369 * the file type from the file name extension. Since the MS entries that 370 * have no type string are very few, and have odd names like "MS-DOS CP 437" 371 * and would never return a Java Font anyway its currently OK to put these 372 * in the font map, although clearly the returned names must never percolate 373 * up into a list of available fonts returned to the application. 374 * Additionally for TTC font files the key looks like 375 * Font 1 & Font 2 (TrueType) 376 * or sometimes even : 377 * Font 1 & Font 2 & Font 3 (TrueType) 378 * Also if a Font has a name for this locale that name also 379 * exists in the registry using the appropriate platform encoding. 380 * What do we do then? 381 * 382 * Note: OpenType fonts seems to have " (TrueType)" suffix on Vista 383 * but " (OpenType)" on XP. 384 */ 385 static BOOL RegistryToBaseTTNameW(LPWSTR name) { 386 static const wchar_t TTSUFFIX[] = L" (TrueType)"; 387 static const wchar_t OTSUFFIX[] = L" (OpenType)"; 388 size_t TTSLEN = wcslen(TTSUFFIX); 389 wchar_t *suffix; 390 391 size_t len = wcslen(name); 392 if (len == 0) { 393 return FALSE; 394 } 395 if (name[len-1] != L')') { 396 return FALSE; 397 } 398 if (len <= TTSLEN) { 399 return FALSE; 400 } 401 /* suffix length is the same for truetype and opentype fonts */ 402 suffix = name + (len - TTSLEN); 403 if (wcscmp(suffix, TTSUFFIX) == 0 || wcscmp(suffix, OTSUFFIX) == 0) { 404 suffix[0] = L'\0'; /* truncate name */ 405 return TRUE; 406 } 407 return FALSE; 408 } 409 410 static void registerFontW(GdiFontMapInfo *fmi, jobject fontToFileMap, 411 LPWSTR name, LPWSTR data) { 412 413 wchar_t *ptr1, *ptr2; 414 jstring fontStr; 415 jstring fontStrLC; 416 JNIEnv *env = fmi->env; 417 size_t dslen = wcslen(data); 418 jstring fileStr = (*env)->NewString(env, data, (jsize)dslen); 419 if (fileStr == NULL) { 420 (*env)->ExceptionClear(env); 421 return; 422 } 423 424 /* TTC or ttc means it may be a collection. Need to parse out 425 * multiple font face names separated by " & " 426 * By only doing this for fonts which look like collections based on 427 * file name we are adhering to MS recommendations for font file names 428 * so it seems that we can be sure that this identifies precisely 429 * the MS-supplied truetype collections. 430 * This avoids any potential issues if a TTF file happens to have 431 * a & in the font name (I can't find anything which prohibits this) 432 * and also means we only parse the key in cases we know to be 433 * worthwhile. 434 */ 435 436 if ((data[dslen-1] == L'C' || data[dslen-1] == L'c') && 437 (ptr1 = wcsstr(name, L" & ")) != NULL) { 438 ptr1+=3; 439 while (ptr1 >= name) { /* marginally safer than while (true) */ 440 while ((ptr2 = wcsstr(ptr1, L" & ")) != NULL) { 441 ptr1 = ptr2+3; 442 } 443 fontStr = (*env)->NewString(env, ptr1, (jsize)wcslen(ptr1)); 444 if (fontStr == NULL) { 445 (*env)->ExceptionClear(env); 446 /* Delete the created reference before return */ 447 DeleteLocalReference(env, fileStr); 448 return; 449 } 450 451 fontStrLC = (*env)->CallObjectMethod(env, fontStr, 452 fmi->toLowerCaseMID, 453 fmi->locale); 454 /* Delete the created reference after its usage */ 455 DeleteLocalReference(env, fontStr); 456 if ((*env)->ExceptionCheck(env)) { 457 /* Delete the created reference before return */ 458 DeleteLocalReference(env, fileStr); 459 return; 460 } 461 462 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 463 fontStrLC, fileStr); 464 /* Delete the reference after its usage */ 465 DeleteLocalReference(env, fontStrLC); 466 if ((*env)->ExceptionCheck(env)) { 467 /* Delete the created reference before return */ 468 DeleteLocalReference(env, fileStr); 469 return; 470 } 471 472 if (ptr1 == name) { 473 break; 474 } else { 475 *(ptr1-3) = L'\0'; 476 ptr1 = name; 477 } 478 } 479 } else { 480 fontStr = (*env)->NewString(env, name, (jsize)wcslen(name)); 481 if (fontStr == NULL) { 482 (*env)->ExceptionClear(env); 483 /* Delete the created reference before return */ 484 DeleteLocalReference(env, fileStr); 485 return; 486 } 487 488 fontStrLC = (*env)->CallObjectMethod(env, fontStr, 489 fmi->toLowerCaseMID, fmi->locale); 490 /* Delete the created reference after its usage */ 491 DeleteLocalReference(env, fontStr); 492 if ((*env)->ExceptionCheck(env)) { 493 /* Delete the created reference before return */ 494 DeleteLocalReference(env, fileStr); 495 return; 496 } 497 498 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 499 fontStrLC, fileStr); 500 /* Delete the created reference after its usage */ 501 DeleteLocalReference(env, fontStrLC); 502 if ((*env)->ExceptionCheck(env)) { 503 /* Delete the created reference before return */ 504 DeleteLocalReference(env, fileStr); 505 return; 506 } 507 } 508 509 /* Delete the created reference after its usage */ 510 DeleteLocalReference(env, fileStr); 511 } 512 513 /* Obtain all the fontname -> filename mappings. 514 * This is called once and the results returned to Java code which can 515 * use it for lookups to reduce or avoid the need to search font files. 516 */ 517 JNIEXPORT void JNICALL 518 Java_sun_awt_Win32FontManager_populateFontFileNameMap0 519 (JNIEnv *env, jclass obj, jobject fontToFileMap, 520 jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale) 521 { 522 #define MAX_BUFFER (FILENAME_MAX+1) 523 const wchar_t wname[MAX_BUFFER]; 524 const char data[MAX_BUFFER]; 525 526 DWORD type; 527 LONG ret; 528 HKEY hkeyFonts; 529 DWORD dwNameSize; 530 DWORD dwDataValueSize; 531 DWORD nval; 532 DWORD dwNumValues, dwMaxValueNameLen, dwMaxValueDataLen; 533 DWORD numValues = 0; 534 jclass classIDHashMap; 535 jclass classIDString; 536 jmethodID putMID; 537 GdiFontMapInfo fmi; 538 539 /* Check we were passed all the maps we need, and do lookup of 540 * methods for JNI up-calls 541 */ 542 if (fontToFileMap == NULL || 543 fontToFamilyMap == NULL || 544 familyToFontListMap == NULL) { 545 return; 546 } 547 classIDHashMap = (*env)->FindClass(env, "java/util/HashMap"); 548 if (classIDHashMap == NULL) { 549 return; 550 } 551 putMID = (*env)->GetMethodID(env, classIDHashMap, "put", 552 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 553 if (putMID == NULL) { 554 return; 555 } 556 557 fmi.env = env; 558 fmi.fontToFamilyMap = fontToFamilyMap; 559 fmi.familyToFontListMap = familyToFontListMap; 560 fmi.putMID = putMID; 561 fmi.locale = locale; 562 fmi.containsKeyMID = (*env)->GetMethodID(env, classIDHashMap, 563 "containsKey", 564 "(Ljava/lang/Object;)Z"); 565 if (fmi.containsKeyMID == NULL) { 566 return; 567 } 568 569 fmi.arrayListClass = (*env)->FindClass(env, "java/util/ArrayList"); 570 if (fmi.arrayListClass == NULL) { 571 return; 572 } 573 fmi.arrayListCtr = (*env)->GetMethodID(env, fmi.arrayListClass, 574 "<init>", "(I)V"); 575 if (fmi.arrayListCtr == NULL) { 576 return; 577 } 578 fmi.addMID = (*env)->GetMethodID(env, fmi.arrayListClass, 579 "add", "(Ljava/lang/Object;)Z"); 580 if (fmi.addMID == NULL) { 581 return; 582 } 583 584 classIDString = (*env)->FindClass(env, "java/lang/String"); 585 if (classIDString == NULL) { 586 return; 587 } 588 fmi.toLowerCaseMID = 589 (*env)->GetMethodID(env, classIDString, "toLowerCase", 590 "(Ljava/util/Locale;)Ljava/lang/String;"); 591 if (fmi.toLowerCaseMID == NULL) { 592 return; 593 } 594 595 screenDC = GetDC(NULL); 596 if (screenDC == NULL) { 597 return; 598 } 599 600 /* Enumerate fonts via GDI to build maps of fonts and families */ 601 LOGFONTW lfw; 602 memset(&lfw, 0, sizeof(lfw)); 603 lfw.lfCharSet = DEFAULT_CHARSET; /* all charsets */ 604 wcscpy(lfw.lfFaceName, L""); /* one face per family (CHECK) */ 605 EnumFontFamiliesExW(screenDC, &lfw, 606 (FONTENUMPROCW)EnumFamilyNamesW, 607 (LPARAM)(&fmi), 0L); 608 609 /* Use the windows registry to map font names to files */ 610 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 611 FONTKEY_NT, 0L, KEY_READ, &hkeyFonts); 612 if (ret != ERROR_SUCCESS) { 613 ReleaseDC(NULL, screenDC); 614 screenDC = NULL; 615 return; 616 } 617 618 ret = RegQueryInfoKeyW(hkeyFonts, NULL, NULL, NULL, NULL, NULL, NULL, 619 &dwNumValues, &dwMaxValueNameLen, 620 &dwMaxValueDataLen, NULL, NULL); 621 622 if (ret != ERROR_SUCCESS || 623 dwMaxValueNameLen >= MAX_BUFFER || 624 dwMaxValueDataLen >= MAX_BUFFER) { 625 RegCloseKey(hkeyFonts); 626 ReleaseDC(NULL, screenDC); 627 screenDC = NULL; 628 return; 629 } 630 for (nval = 0; nval < dwNumValues; nval++ ) { 631 dwNameSize = MAX_BUFFER; 632 dwDataValueSize = MAX_BUFFER; 633 ret = RegEnumValueW(hkeyFonts, nval, (LPWSTR)wname, &dwNameSize, 634 NULL, &type, (LPBYTE)data, &dwDataValueSize); 635 636 if (ret != ERROR_SUCCESS) { 637 break; 638 } 639 if (type != REG_SZ) { /* REG_SZ means a null-terminated string */ 640 continue; 641 } 642 643 if (!RegistryToBaseTTNameW((LPWSTR)wname) ) { 644 /* If the filename ends with ".ttf" or ".otf" also accept it. 645 * Not expecting to need to do this for .ttc files. 646 * Also note this code is not mirrored in the "A" (win9x) path. 647 */ 648 LPWSTR dot = wcsrchr((LPWSTR)data, L'.'); 649 if (dot == NULL || ((wcsicmp(dot, L".ttf") != 0) 650 && (wcsicmp(dot, L".otf") != 0))) { 651 continue; /* not a TT font... */ 652 } 653 } 654 registerFontW(&fmi, fontToFileMap, (LPWSTR)wname, (LPWSTR)data); 655 } 656 657 RegCloseKey(hkeyFonts); 658 ReleaseDC(NULL, screenDC); 659 screenDC = NULL; 660 }