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