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