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