1 /*
   2  * Copyright (c) 1995, 2012, 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         jobjectArray componentFonts = NULL;
 456         jobject peer = NULL;
 457         jobject fontDescriptor = NULL;
 458         jstring fontDescriptorName = NULL;
 459         jstring charsetName = NULL;
 460 
 461         fdata = (struct FontData *) JNU_GetLongFieldAsPtr(env,font,
 462                                                          fontIDs.pData);
 463 
 464         if (fdata != NULL && fdata->flist != NULL) {
 465             return fdata;
 466         }
 467         size = (*env)->GetIntField(env, font, fontIDs.size);
 468         fdata = (struct FontData *) malloc(sizeof(struct FontData));
 469 
 470         peer = (*env)->CallObjectMethod(env, font, fontIDs.getPeer);
 471 
 472         componentFonts =
 473           (*env)->GetObjectField(env, peer, platformFontIDs.componentFonts);
 474         /* We no longer need peer */
 475         (*env)->DeleteLocalRef(env, peer);
 476 
 477         fdata->charset_num = (*env)->GetArrayLength(env, componentFonts);
 478 
 479         fdata->flist = (awtFontList *) malloc(sizeof(awtFontList)
 480                                               * fdata->charset_num);
 481         fdata->xfont = NULL;
 482         for (i = 0; i < fdata->charset_num; i++) {
 483             /*
 484              * set xlfd name
 485              */
 486 
 487             fontDescriptor = (*env)->GetObjectArrayElement(env, componentFonts, i);
 488             fontDescriptorName =
 489               (*env)->GetObjectField(env, fontDescriptor,
 490                                      fontDescriptorIDs.nativeName);
 491 
 492             if (!JNU_IsNull(env, fontDescriptorName)) {
 493                 nativename = (char *) JNU_GetStringPlatformChars(env, fontDescriptorName, NULL);
 494             } else {
 495                 nativename = "";
 496             }
 497 
 498             fdata->flist[i].xlfd = malloc(strlen(nativename)
 499                                           + strlen(defaultXLFD));
 500             jio_snprintf(fdata->flist[i].xlfd, strlen(nativename) + 10,
 501                          nativename, size * 10);
 502 
 503             if (nativename != NULL && nativename != "")
 504                 JNU_ReleaseStringPlatformChars(env, fontDescriptorName, (const char *) nativename);
 505 
 506             /*
 507              * set charset_name
 508              */
 509 
 510             charsetName =
 511               (*env)->GetObjectField(env, fontDescriptor,
 512                                      fontDescriptorIDs.charsetName);
 513 
 514             fdata->flist[i].charset_name = (char *)
 515                 JNU_GetStringPlatformChars(env, charsetName, NULL);
 516 
 517             /* We are done with the objects. */
 518             (*env)->DeleteLocalRef(env, fontDescriptor);
 519             (*env)->DeleteLocalRef(env, fontDescriptorName);
 520             (*env)->DeleteLocalRef(env, charsetName);
 521 
 522             /*
 523              * set load & XFontStruct
 524              */
 525             fdata->flist[i].load = 0;
 526 
 527             /*
 528              * This appears to be a bogus check.  The actual intent appears
 529              * to be to find out whether this is the "base" font in a set,
 530              * rather than iso8859_1 explicitly.  Note that iso8859_15 will
 531              * and must also pass this test.
 532              */
 533 
 534             if (fdata->xfont == NULL &&
 535                 strstr(fdata->flist[i].charset_name, "8859_1")) {
 536                 fdata->flist[i].xfont =
 537                     loadFont(awt_display, fdata->flist[i].xlfd, size * 10);
 538                 if (fdata->flist[i].xfont != NULL) {
 539                     fdata->flist[i].load = 1;
 540                     fdata->xfont = fdata->flist[i].xfont;
 541                     fdata->flist[i].index_length = 1;
 542                 } else {
 543                     /* Free any already allocated storage and fonts */
 544                     int j = i;
 545                     for (j = 0; j <= i; j++) {
 546                         free((void *)fdata->flist[j].xlfd);
 547                         JNU_ReleaseStringPlatformChars(env, NULL,
 548                             fdata->flist[j].charset_name);
 549                         if (fdata->flist[j].load) {
 550                             XFreeFont(awt_display, fdata->flist[j].xfont);
 551                         }
 552                     }
 553                     free((void *)fdata->flist);
 554                     free((void *)fdata);
 555 
 556                     if (errmsg != NULL) {
 557                         *errmsg = "java/lang" "NullPointerException";
 558                     }
 559                     (*env)->DeleteLocalRef(env, componentFonts);
 560                     return NULL;
 561                 }
 562             }
 563         }
 564         (*env)->DeleteLocalRef(env, componentFonts);
 565         /*
 566          * XFontSet will create if the peer of TextField/TextArea
 567          * are used.
 568          */
 569         fdata->xfs = NULL;
 570 
 571         JNU_SetLongFieldFromPtr(env,font,fontIDs.pData,fdata);
 572         Disposer_AddRecord(env, font, pDataDisposeMethod, ptr_to_jlong(fdata));
 573         return fdata;
 574     } else {
 575         Display *display = NULL;
 576         struct FontData *fdata = NULL;
 577         char fontSpec[1024];
 578         int32_t height;
 579         int32_t oheight;
 580         int32_t above = 0;              /* tries above height */
 581         int32_t below = 0;              /* tries below height */
 582         char *foundry = NULL;
 583         char *name = NULL;
 584         char *encoding = NULL;
 585         char *style = NULL;
 586         XFontStruct *xfont = NULL;
 587         jstring family = NULL;
 588 
 589         if (JNU_IsNull(env, font)) {
 590             if (errmsg != NULL) {
 591                 *errmsg = "java/lang" "NullPointerException";
 592             }
 593             return (struct FontData *) NULL;
 594         }
 595         display = XDISPLAY;
 596 
 597         fdata = (struct FontData *) JNU_GetLongFieldAsPtr(env,font,fontIDs.pData);
 598         if (fdata != NULL && fdata->xfont != NULL) {
 599             return fdata;
 600         }
 601 
 602         family = (*env)->CallObjectMethod(env, font, fontIDs.getFamily);
 603 
 604         if (!awtJNI_FontName(env, family, &foundry, &name, &encoding)) {
 605             if (errmsg != NULL) {
 606                 *errmsg = "java/lang" "NullPointerException";
 607             }
 608             (*env)->DeleteLocalRef(env, family);
 609             return (struct FontData *) NULL;
 610         }
 611         style = Style((*env)->GetIntField(env, font, fontIDs.style));
 612         oheight = height = (*env)->GetIntField(env, font, fontIDs.size);
 613 
 614         while (1) {
 615             jio_snprintf(fontSpec, sizeof(fontSpec), "-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
 616                          foundry,
 617                          name,
 618                          style,
 619                          height,
 620                          encoding);
 621 
 622             /*fprintf(stderr,"LoadFont: %s\n", fontSpec); */
 623             xfont = XLoadQueryFont(display, fontSpec);
 624 
 625             /* XXX: sometimes XLoadQueryFont returns a bogus font structure */
 626             /* with negative ascent. */
 627             if (xfont == (Font) NULL || xfont->ascent < 0) {
 628                 if (xfont != NULL) {
 629                     XFreeFont(display, xfont);
 630                 }
 631                 if (foundry != anyfoundry) {  /* Use ptr comparison here, not strcmp */
 632                     /* Try any other foundry before messing with the sizes */
 633                     foundry = anyfoundry;
 634                     continue;
 635                 }
 636                 /* We couldn't find the font. We'll try to find an */
 637                 /* alternate by searching for heights above and below our */
 638                 /* preferred height. We try for 4 heights above and below. */
 639                 /* If we still can't find a font we repeat the algorithm */
 640                 /* using misc-fixed as the font. If we then fail, then we */
 641                 /* give up and signal an error. */
 642                 if (above == below) {
 643                     above++;
 644                     height = oheight + above;
 645                 } else {
 646                     below++;
 647                     if (below > 4) {
 648                         if (name != defaultfontname || style != anystyle) {
 649                             name = defaultfontname;
 650                             foundry = defaultfoundry;
 651                             height = oheight;
 652                             style = anystyle;
 653                             encoding = isolatin1;
 654                             above = below = 0;
 655                             continue;
 656                         } else {
 657                             if (errmsg != NULL) {
 658                                 *errmsg = "java/io/" "FileNotFoundException";
 659                             }
 660                             (*env)->DeleteLocalRef(env, family);
 661                             return (struct FontData *) NULL;
 662                         }
 663                     }
 664                     height = oheight - below;
 665                 }
 666                 continue;
 667             } else {
 668                 fdata = ZALLOC(FontData);
 669 
 670                 if (fdata == NULL) {
 671                     if (errmsg != NULL) {
 672                         *errmsg = "java/lang" "OutOfMemoryError";
 673                     }
 674                 } else {
 675                     fdata->xfont = xfont;
 676                     JNU_SetLongFieldFromPtr(env,font,fontIDs.pData,fdata);
 677                     Disposer_AddRecord(env, font, pDataDisposeMethod,
 678                                        ptr_to_jlong(fdata));
 679                 }
 680                 (*env)->DeleteLocalRef(env, family);
 681                 return fdata;
 682             }
 683         }
 684         /* not reached */
 685     }
 686 }
 687 
 688 /*
 689  * Registered with the 2D disposer to be called after the Font is GC'd.
 690  */
 691 static void pDataDisposeMethod(JNIEnv *env, jlong pData)
 692 {
 693     struct FontData *fdata = NULL;
 694     int32_t i = 0;
 695     Display *display = XDISPLAY;
 696 
 697     AWT_LOCK();
 698     fdata = (struct FontData *)pData;
 699 
 700     if (fdata == NULL) {
 701         AWT_UNLOCK();
 702         return;
 703     }
 704 
 705     if (fdata->xfs != NULL) {
 706         XFreeFontSet(display, fdata->xfs);
 707     }
 708 
 709     /* AWT fonts are always "multifonts" and probably have been in
 710      * all post 1.0 releases, so this test test for multi fonts is
 711      * probably not needed, and the singleton xfont is probably never used.
 712      */
 713     if (fdata->charset_num > 0) {
 714         for (i = 0; i < fdata->charset_num; i++) {
 715             free((void *)fdata->flist[i].xlfd);
 716             JNU_ReleaseStringPlatformChars(env, NULL,
 717                                            fdata->flist[i].charset_name);
 718             if (fdata->flist[i].load) {
 719                 XFreeFont(display, fdata->flist[i].xfont);
 720             }
 721         }
 722 
 723         free((void *)fdata->flist);
 724 
 725         /* Don't free fdata->xfont because it is equal to fdata->flist[i].xfont
 726            for some 'i' */
 727     } else {
 728         if (fdata->xfont != NULL) {
 729             XFreeFont(display, fdata->xfont);
 730         }
 731     }
 732 
 733     free((void *)fdata);
 734 
 735     AWT_UNLOCK();
 736 }
 737 #endif /* !HEADLESS */