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 "Disposer.h"
  39 #endif /* !HEADLESS */
  40 #include <jni.h>
  41 #ifndef HEADLESS
  42 #include <jni_util.h>
  43 
  44 #define defaultXLFD "-*-helvetica-*-*-*-*-12-*-*-*-*-*-iso8859-1"
  45 
  46 struct FontIDs fontIDs;
  47 struct PlatformFontIDs platformFontIDs;
  48 
  49 static void pDataDisposeMethod(JNIEnv *env, jlong pData);
  50 
  51 /* #define FONT_DEBUG 2 */
  52 /* 1- print failures, 2- print all, 3- terminate on failure */
  53 #if FONT_DEBUG
  54 static XFontStruct *XLoadQueryFontX(Display *display, char *name)
  55 {
  56     XFontStruct *result = NULL;
  57     result = XLoadQueryFont(display, name);
  58 #if FONT_DEBUG < 2
  59     if (result == NULL)
  60 #endif
  61         fprintf(stderr, "XLoadQueryFont(\"%s\") -> 0x%x.\n", name, result);
  62 #if FONT_DEBUG >= 3
  63     if (result == NULL)
  64         exit(-1);
  65 #endif
  66     return result;
  67 }
  68 #define XLoadQueryFont XLoadQueryFontX
  69 #endif
  70 #endif /* !HEADLESS */
  71 
  72 /*
  73  * Class:     java_awt_Font
  74  * Method:    initIDs
  75  * Signature: ()V
  76  */
  77 
  78 /* This function gets called from the static initializer for Font.java
  79    to initialize the fieldIDs for fields that may be accessed from C */
  80 
  81 JNIEXPORT void JNICALL
  82 Java_java_awt_Font_initIDs
  83   (JNIEnv *env, jclass cls)
  84 {
  85 #ifndef HEADLESS
  86     CHECK_NULL(fontIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"));
  87     CHECK_NULL(fontIDs.style = (*env)->GetFieldID(env, cls, "style", "I"));
  88     CHECK_NULL(fontIDs.size = (*env)->GetFieldID(env, cls, "size", "I"));
  89     CHECK_NULL(fontIDs.getPeer = (*env)->GetMethodID(env, cls, "getFontPeer",
  90                                                      "()Ljava/awt/peer/FontPeer;"));
  91     CHECK_NULL(fontIDs.getFamily = (*env)->GetMethodID(env, cls, "getFamily_NoClientCode",
  92                                                        "()Ljava/lang/String;"));
  93 #endif /* !HEADLESS */
  94 }
  95 
  96 #ifndef HEADLESS
  97 /* fieldIDs for FontDescriptor fields that may be accessed from C */
  98 static struct FontDescriptorIDs {
  99     jfieldID nativeName;
 100     jfieldID charsetName;
 101 } fontDescriptorIDs;
 102 #endif /* !HEADLESS */
 103 
 104 /*
 105  * Class:     sun_awt_FontDescriptor
 106  * Method:    initIDs
 107  * Signature: ()V
 108  */
 109 
 110 /* This function gets called from the static initializer for
 111    FontDescriptor.java to initialize the fieldIDs for fields
 112    that may be accessed from C */
 113 
 114 JNIEXPORT void JNICALL
 115 Java_sun_awt_FontDescriptor_initIDs
 116   (JNIEnv *env, jclass cls)
 117 {
 118 #ifndef HEADLESS
 119     CHECK_NULL(fontDescriptorIDs.nativeName =
 120                (*env)->GetFieldID(env, cls, "nativeName", "Ljava/lang/String;"));
 121     CHECK_NULL(fontDescriptorIDs.charsetName =
 122                (*env)->GetFieldID(env, cls, "charsetName", "Ljava/lang/String;"));
 123 #endif /* !HEADLESS */
 124 }
 125 
 126 /*
 127  * Class:     sun_awt_PlatformFont
 128  * Method:    initIDs
 129  * Signature: ()V
 130  */
 131 
 132 /* This function gets called from the static initializer for
 133    PlatformFont.java to initialize the fieldIDs for fields
 134    that may be accessed from C */
 135 
 136 JNIEXPORT void JNICALL
 137 Java_sun_awt_PlatformFont_initIDs
 138   (JNIEnv *env, jclass cls)
 139 {
 140 #ifndef HEADLESS
 141     CHECK_NULL(platformFontIDs.componentFonts =
 142                (*env)->GetFieldID(env, cls, "componentFonts",
 143                                   "[Lsun/awt/FontDescriptor;"));
 144     CHECK_NULL(platformFontIDs.fontConfig =
 145                (*env)->GetFieldID(env,cls, "fontConfig",
 146                                   "Lsun/awt/FontConfiguration;"));
 147     CHECK_NULL(platformFontIDs.makeConvertedMultiFontString =
 148                (*env)->GetMethodID(env, cls, "makeConvertedMultiFontString",
 149                                    "(Ljava/lang/String;)[Ljava/lang/Object;"));
 150     CHECK_NULL(platformFontIDs.makeConvertedMultiFontChars =
 151                (*env)->GetMethodID(env, cls, "makeConvertedMultiFontChars",
 152                                    "([CII)[Ljava/lang/Object;"));
 153 #endif /* !HEADLESS */
 154 }
 155 
 156 #ifndef HEADLESS
 157 XFontStruct *
 158 loadFont(Display * display, char *name, int32_t pointSize)
 159 {
 160     XFontStruct *f = NULL;
 161 
 162     /* try the exact xlfd name in font configuration file */
 163     f = XLoadQueryFont(display, name);
 164     if (f != NULL) {
 165         return f;
 166     }
 167 
 168     /*
 169      * try nearly font
 170      *
 171      *  1. specify FAMILY_NAME, WEIGHT_NAME, SLANT, POINT_SIZE,
 172      *     CHARSET_REGISTRY and CHARSET_ENCODING.
 173      *  2. change POINT_SIZE to PIXEL_SIZE
 174      *  3. change FAMILY_NAME to *
 175      *  4. specify only PIXEL_SIZE and CHARSET_REGISTRY/ENCODING
 176      *  5. change PIXEL_SIZE +1/-1/+2/-2...+4/-4
 177      *  6. default font pattern
 178      */
 179     {
 180         /*
 181          * This code assumes the name contains exactly 14 '-' delimiter.
 182          * If not use default pattern.
 183          */
 184         int32_t i, length, pixelSize;
 185         Boolean useDefault = FALSE;
 186 
 187         char buffer[BUFSIZ], buffer2[BUFSIZ];
 188         char *family = NULL, *style = NULL, *slant = NULL, *encoding = NULL;
 189         char *start = NULL, *end = NULL;
 190 
 191         if (strlen(name) > BUFSIZ - 1) {
 192             useDefault = TRUE;
 193         } else {
 194             strcpy(buffer, name);
 195         }
 196 
 197 #define NEXT_HYPHEN\
 198         start = end + 1;\
 199         end = strchr(start, '-');\
 200         if (end == NULL) {\
 201                               useDefault = TRUE;\
 202         break;\
 203         }\
 204         *end = '\0'
 205 
 206              do {
 207                  end = buffer;
 208 
 209                  /* skip FOUNDRY */
 210                  NEXT_HYPHEN;
 211 
 212                  /* set FAMILY_NAME */
 213                  NEXT_HYPHEN;
 214                  family = start;
 215 
 216                  /* set STYLE_NAME */
 217                  NEXT_HYPHEN;
 218                  style = start;
 219 
 220                  /* set SLANT */
 221                  NEXT_HYPHEN;
 222                  slant = start;
 223 
 224                  /* skip SETWIDTH_NAME, ADD_STYLE_NAME, PIXEL_SIZE
 225                     POINT_SIZE, RESOLUTION_X, RESOLUTION_Y, SPACING
 226                     and AVERAGE_WIDTH */
 227                  NEXT_HYPHEN;
 228                  NEXT_HYPHEN;
 229                  NEXT_HYPHEN;
 230                  NEXT_HYPHEN;
 231                  NEXT_HYPHEN;
 232                  NEXT_HYPHEN;
 233                  NEXT_HYPHEN;
 234                  NEXT_HYPHEN;
 235 
 236                  /* set CHARSET_REGISTRY and CHARSET_ENCODING */
 237                  encoding = end + 1;
 238              }
 239              while (0);
 240 
 241 #define TRY_LOAD\
 242         f = XLoadQueryFont(display, buffer2);\
 243         if (f != NULL) {\
 244                             strcpy(name, buffer2);\
 245         return f;\
 246         }
 247 
 248         if (!useDefault) {
 249             char *altstyle = NULL;
 250 
 251             /* Regular is the style for TrueType fonts -- Type1, F3 use roman */
 252             if (strcmp(style, "regular") == 0) {
 253                 altstyle = "roman";
 254             }
 255 #if defined(__linux__) || defined(MACOSX)
 256             if (!strcmp(family, "lucidasans")) {
 257                 family = "lucida";
 258             }
 259 #endif
 260             /* try 1. */
 261             jio_snprintf(buffer2, sizeof(buffer2),
 262                          "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",
 263                          family, style, slant, pointSize, encoding);
 264             TRY_LOAD;
 265 
 266             if (altstyle != NULL) {
 267                 jio_snprintf(buffer2, sizeof(buffer2),
 268                              "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",
 269                              family, altstyle, slant, pointSize, encoding);
 270                 TRY_LOAD;
 271             }
 272 
 273             /* search bitmap font */
 274             pixelSize = pointSize / 10;
 275 
 276             /* try 2. */
 277             jio_snprintf(buffer2, sizeof(buffer2),
 278                          "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
 279                          family, style, slant, pixelSize, encoding);
 280             TRY_LOAD;
 281 
 282             if (altstyle != NULL) {
 283                 jio_snprintf(buffer2, sizeof(buffer2),
 284                              "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
 285                              family, altstyle, slant, pixelSize, encoding);
 286                 TRY_LOAD;
 287             }
 288 
 289             /* try 3 */
 290             jio_snprintf(buffer2, sizeof(buffer2),
 291                          "-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",
 292                          style, slant, pixelSize, encoding);
 293             TRY_LOAD;
 294             if (altstyle != NULL) {
 295                 jio_snprintf(buffer2, sizeof(buffer2),
 296                              "-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",
 297                              altstyle, slant, pixelSize, encoding);
 298                 TRY_LOAD;
 299             }
 300 
 301             /* try 4 */
 302             jio_snprintf(buffer2, sizeof(buffer2),
 303                          "-*-*-*-%s-*-*-%d-*-*-*-*-*-%s",
 304                          slant, pixelSize, encoding);
 305 
 306             TRY_LOAD;
 307 
 308             /* try 5. */
 309             jio_snprintf(buffer2, sizeof(buffer2),
 310                          "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
 311                          pixelSize, encoding);
 312             TRY_LOAD;
 313 
 314             /* try 6. */
 315             for (i = 1; i < 4; i++) {
 316                 if (pixelSize < i)
 317                     break;
 318                 jio_snprintf(buffer2, sizeof(buffer2),
 319                              "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
 320                              family, style, slant, pixelSize + i, encoding);
 321                 TRY_LOAD;
 322 
 323                 jio_snprintf(buffer2, sizeof(buffer2),
 324                              "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
 325                              family, style, slant, pixelSize - i, encoding);
 326                 TRY_LOAD;
 327 
 328                 jio_snprintf(buffer2, sizeof(buffer2),
 329                              "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
 330                              pixelSize + i, encoding);
 331                 TRY_LOAD;
 332 
 333                 jio_snprintf(buffer2, sizeof(buffer2),
 334                              "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
 335                              pixelSize - i, encoding);
 336                 TRY_LOAD;
 337             }
 338         }
 339     }
 340 
 341     strcpy(name, defaultXLFD);
 342     return XLoadQueryFont(display, defaultXLFD);
 343 }
 344 
 345 /*
 346  * Hardwired list of mappings for generic font names "Helvetica",
 347  * "TimesRoman", "Courier", "Dialog", and "DialogInput".
 348  */
 349 static char *defaultfontname = "fixed";
 350 static char *defaultfoundry = "misc";
 351 static char *anyfoundry = "*";
 352 static char *anystyle = "*-*";
 353 static char *isolatin1 = "iso8859-1";
 354 
 355 static char *
 356 Style(int32_t s)
 357 {
 358     switch (s) {
 359         case java_awt_Font_ITALIC:
 360             return "medium-i";
 361         case java_awt_Font_BOLD:
 362             return "bold-r";
 363         case java_awt_Font_BOLD + java_awt_Font_ITALIC:
 364             return "bold-i";
 365         case java_awt_Font_PLAIN:
 366         default:
 367             return "medium-r";
 368     }
 369 }
 370 
 371 static int32_t
 372 awtJNI_FontName(JNIEnv * env, jstring name, char **foundry, char **facename, char **encoding)
 373 {
 374     char *cname = NULL;
 375 
 376     if (JNU_IsNull(env, name)) {
 377         return 0;
 378     }
 379     cname = (char *) JNU_GetStringPlatformChars(env, name, NULL);
 380     if (cname == NULL) {
 381         (*env)->ExceptionClear(env);
 382         JNU_ThrowOutOfMemoryError(env, "Could not create font name");
 383         return 0;
 384     }
 385 
 386     /* additional default font names */
 387     if (strcmp(cname, "serif") == 0) {
 388         *foundry = "adobe";
 389         *facename = "times";
 390         *encoding = isolatin1;
 391     } else if (strcmp(cname, "sansserif") == 0) {
 392         *foundry = "adobe";
 393         *facename = "helvetica";
 394         *encoding = isolatin1;
 395     } else if (strcmp(cname, "monospaced") == 0) {
 396         *foundry = "adobe";
 397         *facename = "courier";
 398         *encoding = isolatin1;
 399     } else if (strcmp(cname, "helvetica") == 0) {
 400         *foundry = "adobe";
 401         *facename = "helvetica";
 402         *encoding = isolatin1;
 403     } else if (strcmp(cname, "timesroman") == 0) {
 404         *foundry = "adobe";
 405         *facename = "times";
 406         *encoding = isolatin1;
 407     } else if (strcmp(cname, "courier") == 0) {
 408         *foundry = "adobe";
 409         *facename = "courier";
 410         *encoding = isolatin1;
 411     } else if (strcmp(cname, "dialog") == 0) {
 412         *foundry = "b&h";
 413         *facename = "lucida";
 414         *encoding = isolatin1;
 415     } else if (strcmp(cname, "dialoginput") == 0) {
 416         *foundry = "b&h";
 417         *facename = "lucidatypewriter";
 418         *encoding = isolatin1;
 419     } else if (strcmp(cname, "zapfdingbats") == 0) {
 420         *foundry = "itc";
 421         *facename = "zapfdingbats";
 422         *encoding = "*-*";
 423     } else {
 424 #ifdef DEBUG
 425         jio_fprintf(stderr, "Unknown font: %s\n", cname);
 426 #endif
 427         *foundry = defaultfoundry;
 428         *facename = defaultfontname;
 429         *encoding = isolatin1;
 430     }
 431 
 432     if (cname != NULL)
 433         JNU_ReleaseStringPlatformChars(env, name, (const char *) cname);
 434 
 435     return 1;
 436 }
 437 
 438 /*
 439  * Registered with the 2D disposer to be called after the Font is GC'd.
 440  */
 441 static void pDataDisposeMethod(JNIEnv *env, jlong pData)
 442 {
 443     struct FontData *fdata = NULL;
 444     int32_t i = 0;
 445     Display *display = XDISPLAY;
 446 
 447     AWT_LOCK();
 448     fdata = (struct FontData *)pData;
 449 
 450     if (fdata == NULL) {
 451         AWT_UNLOCK();
 452         return;
 453     }
 454 
 455     if (fdata->xfs != NULL) {
 456         XFreeFontSet(display, fdata->xfs);
 457     }
 458 
 459     /* AWT fonts are always "multifonts" and probably have been in
 460      * all post 1.0 releases, so this test for multi fonts is
 461      * probably not needed, and the singleton xfont is probably never used.
 462      */
 463     if (fdata->charset_num > 0) {
 464         for (i = 0; i < fdata->charset_num; i++) {
 465             free((void *)fdata->flist[i].xlfd);
 466             JNU_ReleaseStringPlatformChars(env, NULL,
 467                                            fdata->flist[i].charset_name);
 468             if (fdata->flist[i].load) {
 469                 XFreeFont(display, fdata->flist[i].xfont);
 470             }
 471         }
 472 
 473         free((void *)fdata->flist);
 474 
 475         /* Don't free fdata->xfont because it is equal to fdata->flist[i].xfont
 476            for some 'i' */
 477     } else {
 478         if (fdata->xfont != NULL) {
 479             XFreeFont(display, fdata->xfont);
 480         }
 481     }
 482 
 483     free((void *)fdata);
 484 
 485     AWT_UNLOCK();
 486 }
 487 #endif /* !HEADLESS */