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