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     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 */
  99 static 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 
 115 JNIEXPORT void JNICALL
 116 Java_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 
 137 JNIEXPORT void JNICALL
 138 Java_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
 158 XFontStruct *
 159 loadFont(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  */
 350 static char *defaultfontname = "fixed";
 351 static char *defaultfoundry = "misc";
 352 static char *anyfoundry = "*";
 353 static char *anystyle = "*-*";
 354 static char *isolatin1 = "iso8859-1";
 355 
 356 static char *
 357 Style(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 
 372 static int32_t
 373 awtJNI_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 
 439 struct FontData *
 440 awtJNI_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 == 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  */
 705 static 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 */