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