1/*
2 * Copyright (c) 1995, 2014, 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#ifndef HEADLESS
27
28#include "awt_p.h"
29#include <string.h>
30#include "java_awt_Component.h"
31#include "java_awt_Font.h"
32#include "java_awt_FontMetrics.h"
33#include "sun_awt_X11GraphicsEnvironment.h"
34
35#include "awt_Font.h"
36
37#include "java_awt_Dimension.h"
38#include "multi_font.h"
39#include "Disposer.h"
40#endif /* !HEADLESS */
41#include <jni.h>
42#ifndef HEADLESS
43#include <jni_util.h>
44
45#define defaultXLFD "-*-helvetica-*-*-*-*-12-*-*-*-*-*-iso8859-1"
46
47struct FontIDs fontIDs;
48struct PlatformFontIDs platformFontIDs;
49
50static void pDataDisposeMethod(JNIEnv *env, jlong pData);
51
52/* #define FONT_DEBUG 2 */
53/* 1- print failures, 2- print all, 3- terminate on failure */
54#if FONT_DEBUG
55static XFontStruct *XLoadQueryFontX(Display *display, char *name)
56{
57    XFontStruct *result = NULL;
58    result = XLoadQueryFont(display, name);
59#if FONT_DEBUG < 2
60    if (result == NULL)
61#endif
62        fprintf(stderr, "XLoadQueryFont(\"%s\") -> 0x%x.\n", name, result);
63#if FONT_DEBUG >= 3
64    if (result == NULL)
65        exit(-1);
66#endif
67    return result;
68}
69#define XLoadQueryFont XLoadQueryFontX
70#endif
71#endif /* !HEADLESS */
72
73/*
74 * Class:     java_awt_Font
75 * Method:    initIDs
76 * Signature: ()V
77 */
78
79/* This function gets called from the static initializer for Font.java
80   to initialize the fieldIDs for fields that may be accessed from C */
81
82JNIEXPORT void JNICALL
83Java_java_awt_Font_initIDs
84  (JNIEnv *env, jclass cls)
85{
86#ifndef HEADLESS
87    CHECK_NULL(fontIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"));
88    CHECK_NULL(fontIDs.style = (*env)->GetFieldID(env, cls, "style", "I"));
89    CHECK_NULL(fontIDs.size = (*env)->GetFieldID(env, cls, "size", "I"));
90    CHECK_NULL(fontIDs.getPeer = (*env)->GetMethodID(env, cls, "getFontPeer",
91                                                     "()Ljava/awt/peer/FontPeer;"));
92    CHECK_NULL(fontIDs.getFamily = (*env)->GetMethodID(env, cls, "getFamily_NoClientCode",
93                                                       "()Ljava/lang/String;"));
94#endif /* !HEADLESS */
95}
96
97#ifndef HEADLESS
98/* fieldIDs for FontDescriptor fields that may be accessed from C */
99static struct FontDescriptorIDs {
100    jfieldID nativeName;
101    jfieldID charsetName;
102} fontDescriptorIDs;
103#endif /* !HEADLESS */
104
105/*
106 * Class:     sun_awt_FontDescriptor
107 * Method:    initIDs
108 * Signature: ()V
109 */
110
111/* This function gets called from the static initializer for
112   FontDescriptor.java to initialize the fieldIDs for fields
113   that may be accessed from C */
114
115JNIEXPORT void JNICALL
116Java_sun_awt_FontDescriptor_initIDs
117  (JNIEnv *env, jclass cls)
118{
119#ifndef HEADLESS
120    CHECK_NULL(fontDescriptorIDs.nativeName =
121               (*env)->GetFieldID(env, cls, "nativeName", "Ljava/lang/String;"));
122    CHECK_NULL(fontDescriptorIDs.charsetName =
123               (*env)->GetFieldID(env, cls, "charsetName", "Ljava/lang/String;"));
124#endif /* !HEADLESS */
125}
126
127/*
128 * Class:     sun_awt_PlatformFont
129 * Method:    initIDs
130 * Signature: ()V
131 */
132
133/* This function gets called from the static initializer for
134   PlatformFont.java to initialize the fieldIDs for fields
135   that may be accessed from C */
136
137JNIEXPORT void JNICALL
138Java_sun_awt_PlatformFont_initIDs
139  (JNIEnv *env, jclass cls)
140{
141#ifndef HEADLESS
142    CHECK_NULL(platformFontIDs.componentFonts =
143               (*env)->GetFieldID(env, cls, "componentFonts",
144                                  "[Lsun/awt/FontDescriptor;"));
145    CHECK_NULL(platformFontIDs.fontConfig =
146               (*env)->GetFieldID(env,cls, "fontConfig",
147                                  "Lsun/awt/FontConfiguration;"));
148    CHECK_NULL(platformFontIDs.makeConvertedMultiFontString =
149               (*env)->GetMethodID(env, cls, "makeConvertedMultiFontString",
150                                   "(Ljava/lang/String;)[Ljava/lang/Object;"));
151    CHECK_NULL(platformFontIDs.makeConvertedMultiFontChars =
152               (*env)->GetMethodID(env, cls, "makeConvertedMultiFontChars",
153                                   "([CII)[Ljava/lang/Object;"));
154#endif /* !HEADLESS */
155}
156
157#ifndef HEADLESS
158XFontStruct *
159loadFont(Display * display, char *name, int32_t pointSize)
160{
161    XFontStruct *f = NULL;
162
163    /* try the exact xlfd name in font configuration file */
164    f = XLoadQueryFont(display, name);
165    if (f != NULL) {
166        return f;
167    }
168
169    /*
170     * try nearly font
171     *
172     *  1. specify FAMILY_NAME, WEIGHT_NAME, SLANT, POINT_SIZE,
173     *     CHARSET_REGISTRY and CHARSET_ENCODING.
174     *  2. change POINT_SIZE to PIXEL_SIZE
175     *  3. change FAMILY_NAME to *
176     *  4. specify only PIXEL_SIZE and CHARSET_REGISTRY/ENCODING
177     *  5. change PIXEL_SIZE +1/-1/+2/-2...+4/-4
178     *  6. default font pattern
179     */
180    {
181        /*
182         * This code assumes the name contains exactly 14 '-' delimiter.
183         * If not use default pattern.
184         */
185        int32_t i, length, pixelSize;
186        Boolean useDefault = FALSE;
187
188        char buffer[BUFSIZ], buffer2[BUFSIZ];
189        char *family = NULL, *style = NULL, *slant = NULL, *encoding = NULL;
190        char *start = NULL, *end = NULL;
191
192        if (strlen(name) > BUFSIZ - 1) {
193            useDefault = TRUE;
194        } else {
195            strcpy(buffer, name);
196        }
197
198#define NEXT_HYPHEN\
199        start = end + 1;\
200        end = strchr(start, '-');\
201        if (end == NULL) {\
202                              useDefault = TRUE;\
203        break;\
204        }\
205        *end = '\0'
206
207             do {
208                 end = buffer;
209
210                 /* skip FOUNDRY */
211                 NEXT_HYPHEN;
212
213                 /* set FAMILY_NAME */
214                 NEXT_HYPHEN;
215                 family = start;
216
217                 /* set STYLE_NAME */
218                 NEXT_HYPHEN;
219                 style = start;
220
221                 /* set SLANT */
222                 NEXT_HYPHEN;
223                 slant = start;
224
225                 /* skip SETWIDTH_NAME, ADD_STYLE_NAME, PIXEL_SIZE
226                    POINT_SIZE, RESOLUTION_X, RESOLUTION_Y, SPACING
227                    and AVERAGE_WIDTH */
228                 NEXT_HYPHEN;
229                 NEXT_HYPHEN;
230                 NEXT_HYPHEN;
231                 NEXT_HYPHEN;
232                 NEXT_HYPHEN;
233                 NEXT_HYPHEN;
234                 NEXT_HYPHEN;
235                 NEXT_HYPHEN;
236
237                 /* set CHARSET_REGISTRY and CHARSET_ENCODING */
238                 encoding = end + 1;
239             }
240             while (0);
241
242#define TRY_LOAD\
243        f = XLoadQueryFont(display, buffer2);\
244        if (f != NULL) {\
245                            strcpy(name, buffer2);\
246        return f;\
247        }
248
249        if (!useDefault) {
250            char *altstyle = NULL;
251
252            /* Regular is the style for TrueType fonts -- Type1, F3 use roman */
253            if (strcmp(style, "regular") == 0) {
254                altstyle = "roman";
255            }
256#if defined(__linux__) || defined(MACOSX)
257            if (!strcmp(family, "lucidasans")) {
258                family = "lucida";
259            }
260#endif
261            /* try 1. */
262            jio_snprintf(buffer2, sizeof(buffer2),
263                         "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",
264                         family, style, slant, pointSize, encoding);
265            TRY_LOAD;
266
267            if (altstyle != NULL) {
268                jio_snprintf(buffer2, sizeof(buffer2),
269                             "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",
270                             family, altstyle, slant, pointSize, encoding);
271                TRY_LOAD;
272            }
273
274            /* search bitmap font */
275            pixelSize = pointSize / 10;
276
277            /* try 2. */
278            jio_snprintf(buffer2, sizeof(buffer2),
279                         "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
280                         family, style, slant, pixelSize, encoding);
281            TRY_LOAD;
282
283            if (altstyle != NULL) {
284                jio_snprintf(buffer2, sizeof(buffer2),
285                             "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
286                             family, altstyle, slant, pixelSize, encoding);
287                TRY_LOAD;
288            }
289
290            /* try 3 */
291            jio_snprintf(buffer2, sizeof(buffer2),
292                         "-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",
293                         style, slant, pixelSize, encoding);
294            TRY_LOAD;
295            if (altstyle != NULL) {
296                jio_snprintf(buffer2, sizeof(buffer2),
297                             "-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",
298                             altstyle, slant, pixelSize, encoding);
299                TRY_LOAD;
300            }
301
302            /* try 4 */
303            jio_snprintf(buffer2, sizeof(buffer2),
304                         "-*-*-*-%s-*-*-%d-*-*-*-*-*-%s",
305                         slant, pixelSize, encoding);
306
307            TRY_LOAD;
308
309            /* try 5. */
310            jio_snprintf(buffer2, sizeof(buffer2),
311                         "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
312                         pixelSize, encoding);
313            TRY_LOAD;
314
315            /* try 6. */
316            for (i = 1; i < 4; i++) {
317                if (pixelSize < i)
318                    break;
319                jio_snprintf(buffer2, sizeof(buffer2),
320                             "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
321                             family, style, slant, pixelSize + i, encoding);
322                TRY_LOAD;
323
324                jio_snprintf(buffer2, sizeof(buffer2),
325                             "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
326                             family, style, slant, pixelSize - i, encoding);
327                TRY_LOAD;
328
329                jio_snprintf(buffer2, sizeof(buffer2),
330                             "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
331                             pixelSize + i, encoding);
332                TRY_LOAD;
333
334                jio_snprintf(buffer2, sizeof(buffer2),
335                             "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
336                             pixelSize - i, encoding);
337                TRY_LOAD;
338            }
339        }
340    }
341
342    strcpy(name, defaultXLFD);
343    return XLoadQueryFont(display, defaultXLFD);
344}
345
346/*
347 * Hardwired list of mappings for generic font names "Helvetica",
348 * "TimesRoman", "Courier", "Dialog", and "DialogInput".
349 */
350static char *defaultfontname = "fixed";
351static char *defaultfoundry = "misc";
352static char *anyfoundry = "*";
353static char *anystyle = "*-*";
354static char *isolatin1 = "iso8859-1";
355
356static char *
357Style(int32_t s)
358{
359    switch (s) {
360        case java_awt_Font_ITALIC:
361            return "medium-i";
362        case java_awt_Font_BOLD:
363            return "bold-r";
364        case java_awt_Font_BOLD + java_awt_Font_ITALIC:
365            return "bold-i";
366        case java_awt_Font_PLAIN:
367        default:
368            return "medium-r";
369    }
370}
371
372static int32_t
373awtJNI_FontName(JNIEnv * env, jstring name, char **foundry, char **facename, char **encoding)
374{
375    char *cname = NULL;
376
377    if (JNU_IsNull(env, name)) {
378        return 0;
379    }
380    cname = (char *) JNU_GetStringPlatformChars(env, name, NULL);
381    if (cname == NULL) {
382        (*env)->ExceptionClear(env);
383        JNU_ThrowOutOfMemoryError(env, "Could not create font name");
384        return 0;
385    }
386
387    /* additional default font names */
388    if (strcmp(cname, "serif") == 0) {
389        *foundry = "adobe";
390        *facename = "times";
391        *encoding = isolatin1;
392    } else if (strcmp(cname, "sansserif") == 0) {
393        *foundry = "adobe";
394        *facename = "helvetica";
395        *encoding = isolatin1;
396    } else if (strcmp(cname, "monospaced") == 0) {
397        *foundry = "adobe";
398        *facename = "courier";
399        *encoding = isolatin1;
400    } else if (strcmp(cname, "helvetica") == 0) {
401        *foundry = "adobe";
402        *facename = "helvetica";
403        *encoding = isolatin1;
404    } else if (strcmp(cname, "timesroman") == 0) {
405        *foundry = "adobe";
406        *facename = "times";
407        *encoding = isolatin1;
408    } else if (strcmp(cname, "courier") == 0) {
409        *foundry = "adobe";
410        *facename = "courier";
411        *encoding = isolatin1;
412    } else if (strcmp(cname, "dialog") == 0) {
413        *foundry = "b&h";
414        *facename = "lucida";
415        *encoding = isolatin1;
416    } else if (strcmp(cname, "dialoginput") == 0) {
417        *foundry = "b&h";
418        *facename = "lucidatypewriter";
419        *encoding = isolatin1;
420    } else if (strcmp(cname, "zapfdingbats") == 0) {
421        *foundry = "itc";
422        *facename = "zapfdingbats";
423        *encoding = "*-*";
424    } else {
425#ifdef DEBUG
426        jio_fprintf(stderr, "Unknown font: %s\n", cname);
427#endif
428        *foundry = defaultfoundry;
429        *facename = defaultfontname;
430        *encoding = isolatin1;
431    }
432
433    if (cname != NULL)
434        JNU_ReleaseStringPlatformChars(env, name, (const char *) cname);
435
436    return 1;
437}
438
439struct FontData *
440awtJNI_GetFontData(JNIEnv * env, jobject font, char **errmsg)
441{
442    /* We are going to create at most 4 outstanding local refs in this
443     * function. */
444    if ((*env)->EnsureLocalCapacity(env, 4) < 0) {
445        return NULL;
446    }
447
448    if (!JNU_IsNull(env, font) && awtJNI_IsMultiFont(env, font)) {
449        JNU_CHECK_EXCEPTION_RETURN(env, NULL);
450
451        struct FontData *fdata = NULL;
452        int32_t i, size;
453        char *fontsetname = NULL;
454        char *nativename = NULL;
455        Boolean doFree = FALSE;
456        jobjectArray componentFonts = NULL;
457        jobject peer = NULL;
458        jobject fontDescriptor = NULL;
459        jstring fontDescriptorName = NULL;
460        jstring charsetName = NULL;
461
462        fdata = (struct FontData *) JNU_GetLongFieldAsPtr(env,font,
463                                                         fontIDs.pData);
464
465        if (fdata != NULL && fdata->flist != NULL) {
466            return fdata;
467        }
468        size = (*env)->GetIntField(env, font, fontIDs.size);
469        fdata = (struct FontData *) malloc(sizeof(struct FontData));
470
471        peer = (*env)->CallObjectMethod(env, font, fontIDs.getPeer);
472
473        componentFonts =
474          (*env)->GetObjectField(env, peer, platformFontIDs.componentFonts);
475        /* We no longer need peer */
476        (*env)->DeleteLocalRef(env, peer);
477
478        fdata->charset_num = (*env)->GetArrayLength(env, componentFonts);
479
480        fdata->flist = (awtFontList *) malloc(sizeof(awtFontList)
481                                              * fdata->charset_num);
482        fdata->xfont = NULL;
483        for (i = 0; i < fdata->charset_num; i++) {
484            /*
485             * set xlfd name
486             */
487
488            fontDescriptor = (*env)->GetObjectArrayElement(env, componentFonts, i);
489            fontDescriptorName =
490              (*env)->GetObjectField(env, fontDescriptor,
491                                     fontDescriptorIDs.nativeName);
492
493            if (!JNU_IsNull(env, fontDescriptorName)) {
494                nativename = (char *) JNU_GetStringPlatformChars(env, fontDescriptorName, NULL);
495                if (nativename == NULL) {
496                    nativename = "";
497                    doFree = FALSE;
498                } else {
499                    doFree = TRUE;
500                }
501            } else {
502                nativename = "";
503                doFree = FALSE;
504            }
505
506            fdata->flist[i].xlfd = malloc(strlen(nativename)
507                                          + strlen(defaultXLFD));
508            jio_snprintf(fdata->flist[i].xlfd, strlen(nativename) + 10,
509                         nativename, size * 10);
510
511            if (nativename != NULL && doFree)
512                JNU_ReleaseStringPlatformChars(env, fontDescriptorName, (const char *) nativename);
513
514            /*
515             * set charset_name
516             */
517
518            charsetName =
519              (*env)->GetObjectField(env, fontDescriptor,
520                                     fontDescriptorIDs.charsetName);
521
522            fdata->flist[i].charset_name = (char *)
523                JNU_GetStringPlatformChars(env, charsetName, NULL);
524            if (fdata->flist[i].charset_name == NULL) {
525                (*env)->ExceptionClear(env);
526                JNU_ThrowOutOfMemoryError(env, "Could not create charset name");
527                return NULL;
528            }
529
530            /* We are done with the objects. */
531            (*env)->DeleteLocalRef(env, fontDescriptor);
532            (*env)->DeleteLocalRef(env, fontDescriptorName);
533            (*env)->DeleteLocalRef(env, charsetName);
534
535            /*
536             * set load & XFontStruct
537             */
538            fdata->flist[i].load = 0;
539
540            /*
541             * This appears to be a bogus check.  The actual intent appears
542             * to be to find out whether this is the "base" font in a set,
543             * rather than iso8859_1 explicitly.  Note that iso8859_15 will
544             * and must also pass this test.
545             */
546
547            if (fdata->xfont == NULL &&
548                strstr(fdata->flist[i].charset_name, "8859_1")) {
549                fdata->flist[i].xfont =
550                    loadFont(awt_display, fdata->flist[i].xlfd, size * 10);
551                if (fdata->flist[i].xfont != NULL) {
552                    fdata->flist[i].load = 1;
553                    fdata->xfont = fdata->flist[i].xfont;
554                    fdata->flist[i].index_length = 1;
555                } else {
556                    /* Free any already allocated storage and fonts */
557                    int j = i;
558                    for (j = 0; j <= i; j++) {
559                        free((void *)fdata->flist[j].xlfd);
560                        JNU_ReleaseStringPlatformChars(env, NULL,
561                            fdata->flist[j].charset_name);
562                        if (fdata->flist[j].load) {
563                            XFreeFont(awt_display, fdata->flist[j].xfont);
564                        }
565                    }
566                    free((void *)fdata->flist);
567                    free((void *)fdata);
568
569                    if (errmsg != NULL) {
570                        *errmsg = "java/lang" "NullPointerException";
571                    }
572                    (*env)->DeleteLocalRef(env, componentFonts);
573                    return NULL;
574                }
575            }
576        }
577        (*env)->DeleteLocalRef(env, componentFonts);
578        /*
579         * XFontSet will create if the peer of TextField/TextArea
580         * are used.
581         */
582        fdata->xfs = NULL;
583
584        JNU_SetLongFieldFromPtr(env,font,fontIDs.pData,fdata);
585        Disposer_AddRecord(env, font, pDataDisposeMethod, ptr_to_jlong(fdata));
586        return fdata;
587    } else {
588        JNU_CHECK_EXCEPTION_RETURN(env, NULL);
589        Display *display = NULL;
590        struct FontData *fdata = NULL;
591        char fontSpec[1024];
592        int32_t height;
593        int32_t oheight;
594        int32_t above = 0;              /* tries above height */
595        int32_t below = 0;              /* tries below height */
596        char *foundry = NULL;
597        char *name = NULL;
598        char *encoding = NULL;
599        char *style = NULL;
600        XFontStruct *xfont = NULL;
601        jstring family = NULL;
602
603        if (JNU_IsNull(env, font)) {
604            if (errmsg != NULL) {
605                *errmsg = "java/lang" "NullPointerException";
606            }
607            return (struct FontData *) NULL;
608        }
609        display = XDISPLAY;
610
611        fdata = (struct FontData *) JNU_GetLongFieldAsPtr(env,font,fontIDs.pData);
612        if (fdata != NULL && fdata->xfont != NULL) {
613            return fdata;
614        }
615
616        family = (*env)->CallObjectMethod(env, font, fontIDs.getFamily);
617
618        if (!awtJNI_FontName(env, family, &foundry, &name, &encoding)) {
619            if (errmsg != NULL) {
620                *errmsg = "java/lang" "NullPointerException";
621            }
622            (*env)->DeleteLocalRef(env, family);
623            return (struct FontData *) NULL;
624        }
625        style = Style((*env)->GetIntField(env, font, fontIDs.style));
626        oheight = height = (*env)->GetIntField(env, font, fontIDs.size);
627
628        while (1) {
629            jio_snprintf(fontSpec, sizeof(fontSpec), "-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
630                         foundry,
631                         name,
632                         style,
633                         height,
634                         encoding);
635
636            /*fprintf(stderr,"LoadFont: %s\n", fontSpec); */
637            xfont = XLoadQueryFont(display, fontSpec);
638
639            /* XXX: sometimes XLoadQueryFont returns a bogus font structure */
640            /* with negative ascent. */
641            if (xfont == (Font) NULL || xfont->ascent < 0) {
642                if (xfont != NULL) {
643                    XFreeFont(display, xfont);
644                }
645                if (foundry != anyfoundry) {  /* Use ptr comparison here, not strcmp */
646                    /* Try any other foundry before messing with the sizes */
647                    foundry = anyfoundry;
648                    continue;
649                }
650                /* We couldn't find the font. We'll try to find an */
651                /* alternate by searching for heights above and below our */
652                /* preferred height. We try for 4 heights above and below. */
653                /* If we still can't find a font we repeat the algorithm */
654                /* using misc-fixed as the font. If we then fail, then we */
655                /* give up and signal an error. */
656                if (above == below) {
657                    above++;
658                    height = oheight + above;
659                } else {
660                    below++;
661                    if (below > 4) {
662                        if (name != defaultfontname || style != anystyle) {
663                            name = defaultfontname;
664                            foundry = defaultfoundry;
665                            height = oheight;
666                            style = anystyle;
667                            encoding = isolatin1;
668                            above = below = 0;
669                            continue;
670                        } else {
671                            if (errmsg != NULL) {
672                                *errmsg = "java/io/" "FileNotFoundException";
673                            }
674                            (*env)->DeleteLocalRef(env, family);
675                            return (struct FontData *) NULL;
676                        }
677                    }
678                    height = oheight - below;
679                }
680                continue;
681            } else {
682                fdata = ZALLOC(FontData);
683
684                if (fdata == NULL) {
685                    if (errmsg != NULL) {
686                        *errmsg = "java/lang" "OutOfMemoryError";
687                    }
688                } else {
689                    fdata->xfont = xfont;
690                    JNU_SetLongFieldFromPtr(env,font,fontIDs.pData,fdata);
691                    Disposer_AddRecord(env, font, pDataDisposeMethod,
692                                       ptr_to_jlong(fdata));
693                }
694                (*env)->DeleteLocalRef(env, family);
695                return fdata;
696            }
697        }
698        /* not reached */
699    }
700}
701
702/*
703 * Registered with the 2D disposer to be called after the Font is GC'd.
704 */
705static void pDataDisposeMethod(JNIEnv *env, jlong pData)
706{
707    struct FontData *fdata = NULL;
708    int32_t i = 0;
709    Display *display = XDISPLAY;
710
711    AWT_LOCK();
712    fdata = (struct FontData *)pData;
713
714    if (fdata == NULL) {
715        AWT_UNLOCK();
716        return;
717    }
718
719    if (fdata->xfs != NULL) {
720        XFreeFontSet(display, fdata->xfs);
721    }
722
723    /* AWT fonts are always "multifonts" and probably have been in
724     * all post 1.0 releases, so this test for multi fonts is
725     * probably not needed, and the singleton xfont is probably never used.
726     */
727    if (fdata->charset_num > 0) {
728        for (i = 0; i < fdata->charset_num; i++) {
729            free((void *)fdata->flist[i].xlfd);
730            JNU_ReleaseStringPlatformChars(env, NULL,
731                                           fdata->flist[i].charset_name);
732            if (fdata->flist[i].load) {
733                XFreeFont(display, fdata->flist[i].xfont);
734            }
735        }
736
737        free((void *)fdata->flist);
738
739        /* Don't free fdata->xfont because it is equal to fdata->flist[i].xfont
740           for some 'i' */
741    } else {
742        if (fdata->xfont != NULL) {
743            XFreeFont(display, fdata->xfont);
744        }
745    }
746
747    free((void *)fdata);
748
749    AWT_UNLOCK();
750}
751#endif /* !HEADLESS */
752