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