src/java.desktop/unix/native/common/awt/awt_Font.c
author serb
Sun, 09 Jun 2019 18:14:48 -0700
changeset 57515 2db64810f4fc
parent 51853 ec62d6cab037
child 58598 bdf0a922ae8a
permissions -rw-r--r--
8224171: The cleanup multi-font related code in the XFontPeer Reviewed-by: prr

/*
 * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#ifndef HEADLESS

#include "awt_p.h"
#include <string.h>
#include "java_awt_Component.h"
#include "java_awt_Font.h"
#include "java_awt_FontMetrics.h"
#include "sun_awt_X11GraphicsEnvironment.h"

#include "awt_Font.h"

#include "java_awt_Dimension.h"
#include "Disposer.h"
#endif /* !HEADLESS */
#include <jni.h>
#ifndef HEADLESS
#include <jni_util.h>

#define defaultXLFD "-*-helvetica-*-*-*-*-12-*-*-*-*-*-iso8859-1"

struct FontIDs fontIDs;
struct PlatformFontIDs platformFontIDs;

static void pDataDisposeMethod(JNIEnv *env, jlong pData);

/* #define FONT_DEBUG 2 */
/* 1- print failures, 2- print all, 3- terminate on failure */
#if FONT_DEBUG
static XFontStruct *XLoadQueryFontX(Display *display, char *name)
{
    XFontStruct *result = NULL;
    result = XLoadQueryFont(display, name);
#if FONT_DEBUG < 2
    if (result == NULL)
#endif
        fprintf(stderr, "XLoadQueryFont(\"%s\") -> 0x%x.\n", name, result);
#if FONT_DEBUG >= 3
    if (result == NULL)
        exit(-1);
#endif
    return result;
}
#define XLoadQueryFont XLoadQueryFontX
#endif
#endif /* !HEADLESS */

/*
 * Class:     java_awt_Font
 * Method:    initIDs
 * Signature: ()V
 */

/* This function gets called from the static initializer for Font.java
   to initialize the fieldIDs for fields that may be accessed from C */

JNIEXPORT void JNICALL
Java_java_awt_Font_initIDs
  (JNIEnv *env, jclass cls)
{
#ifndef HEADLESS
    CHECK_NULL(fontIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"));
    CHECK_NULL(fontIDs.style = (*env)->GetFieldID(env, cls, "style", "I"));
    CHECK_NULL(fontIDs.size = (*env)->GetFieldID(env, cls, "size", "I"));
    CHECK_NULL(fontIDs.getPeer = (*env)->GetMethodID(env, cls, "getFontPeer",
                                                     "()Ljava/awt/peer/FontPeer;"));
    CHECK_NULL(fontIDs.getFamily = (*env)->GetMethodID(env, cls, "getFamily_NoClientCode",
                                                       "()Ljava/lang/String;"));
#endif /* !HEADLESS */
}

#ifndef HEADLESS
/* fieldIDs for FontDescriptor fields that may be accessed from C */
static struct FontDescriptorIDs {
    jfieldID nativeName;
    jfieldID charsetName;
} fontDescriptorIDs;
#endif /* !HEADLESS */

/*
 * Class:     sun_awt_FontDescriptor
 * Method:    initIDs
 * Signature: ()V
 */

/* This function gets called from the static initializer for
   FontDescriptor.java to initialize the fieldIDs for fields
   that may be accessed from C */

JNIEXPORT void JNICALL
Java_sun_awt_FontDescriptor_initIDs
  (JNIEnv *env, jclass cls)
{
#ifndef HEADLESS
    CHECK_NULL(fontDescriptorIDs.nativeName =
               (*env)->GetFieldID(env, cls, "nativeName", "Ljava/lang/String;"));
    CHECK_NULL(fontDescriptorIDs.charsetName =
               (*env)->GetFieldID(env, cls, "charsetName", "Ljava/lang/String;"));
#endif /* !HEADLESS */
}

/*
 * Class:     sun_awt_PlatformFont
 * Method:    initIDs
 * Signature: ()V
 */

/* This function gets called from the static initializer for
   PlatformFont.java to initialize the fieldIDs for fields
   that may be accessed from C */

JNIEXPORT void JNICALL
Java_sun_awt_PlatformFont_initIDs
  (JNIEnv *env, jclass cls)
{
#ifndef HEADLESS
    CHECK_NULL(platformFontIDs.componentFonts =
               (*env)->GetFieldID(env, cls, "componentFonts",
                                  "[Lsun/awt/FontDescriptor;"));
    CHECK_NULL(platformFontIDs.fontConfig =
               (*env)->GetFieldID(env,cls, "fontConfig",
                                  "Lsun/awt/FontConfiguration;"));
    CHECK_NULL(platformFontIDs.makeConvertedMultiFontString =
               (*env)->GetMethodID(env, cls, "makeConvertedMultiFontString",
                                   "(Ljava/lang/String;)[Ljava/lang/Object;"));
    CHECK_NULL(platformFontIDs.makeConvertedMultiFontChars =
               (*env)->GetMethodID(env, cls, "makeConvertedMultiFontChars",
                                   "([CII)[Ljava/lang/Object;"));
#endif /* !HEADLESS */
}

#ifndef HEADLESS
XFontStruct *
loadFont(Display * display, char *name, int32_t pointSize)
{
    XFontStruct *f = NULL;

    /* try the exact xlfd name in font configuration file */
    f = XLoadQueryFont(display, name);
    if (f != NULL) {
        return f;
    }

    /*
     * try nearly font
     *
     *  1. specify FAMILY_NAME, WEIGHT_NAME, SLANT, POINT_SIZE,
     *     CHARSET_REGISTRY and CHARSET_ENCODING.
     *  2. change POINT_SIZE to PIXEL_SIZE
     *  3. change FAMILY_NAME to *
     *  4. specify only PIXEL_SIZE and CHARSET_REGISTRY/ENCODING
     *  5. change PIXEL_SIZE +1/-1/+2/-2...+4/-4
     *  6. default font pattern
     */
    {
        /*
         * This code assumes the name contains exactly 14 '-' delimiter.
         * If not use default pattern.
         */
        int32_t i, length, pixelSize;
        Boolean useDefault = FALSE;

        char buffer[BUFSIZ], buffer2[BUFSIZ];
        char *family = NULL, *style = NULL, *slant = NULL, *encoding = NULL;
        char *start = NULL, *end = NULL;

        if (strlen(name) > BUFSIZ - 1) {
            useDefault = TRUE;
        } else {
            strcpy(buffer, name);
        }

#define NEXT_HYPHEN\
        start = end + 1;\
        end = strchr(start, '-');\
        if (end == NULL) {\
                              useDefault = TRUE;\
        break;\
        }\
        *end = '\0'

             do {
                 end = buffer;

                 /* skip FOUNDRY */
                 NEXT_HYPHEN;

                 /* set FAMILY_NAME */
                 NEXT_HYPHEN;
                 family = start;

                 /* set STYLE_NAME */
                 NEXT_HYPHEN;
                 style = start;

                 /* set SLANT */
                 NEXT_HYPHEN;
                 slant = start;

                 /* skip SETWIDTH_NAME, ADD_STYLE_NAME, PIXEL_SIZE
                    POINT_SIZE, RESOLUTION_X, RESOLUTION_Y, SPACING
                    and AVERAGE_WIDTH */
                 NEXT_HYPHEN;
                 NEXT_HYPHEN;
                 NEXT_HYPHEN;
                 NEXT_HYPHEN;
                 NEXT_HYPHEN;
                 NEXT_HYPHEN;
                 NEXT_HYPHEN;
                 NEXT_HYPHEN;

                 /* set CHARSET_REGISTRY and CHARSET_ENCODING */
                 encoding = end + 1;
             }
             while (0);

#define TRY_LOAD\
        f = XLoadQueryFont(display, buffer2);\
        if (f != NULL) {\
                            strcpy(name, buffer2);\
        return f;\
        }

        if (!useDefault) {
            char *altstyle = NULL;

            /* Regular is the style for TrueType fonts -- Type1, F3 use roman */
            if (strcmp(style, "regular") == 0) {
                altstyle = "roman";
            }
#if defined(__linux__) || defined(MACOSX)
            if (!strcmp(family, "lucidasans")) {
                family = "lucida";
            }
#endif
            /* try 1. */
            jio_snprintf(buffer2, sizeof(buffer2),
                         "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",
                         family, style, slant, pointSize, encoding);
            TRY_LOAD;

            if (altstyle != NULL) {
                jio_snprintf(buffer2, sizeof(buffer2),
                             "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",
                             family, altstyle, slant, pointSize, encoding);
                TRY_LOAD;
            }

            /* search bitmap font */
            pixelSize = pointSize / 10;

            /* try 2. */
            jio_snprintf(buffer2, sizeof(buffer2),
                         "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
                         family, style, slant, pixelSize, encoding);
            TRY_LOAD;

            if (altstyle != NULL) {
                jio_snprintf(buffer2, sizeof(buffer2),
                             "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
                             family, altstyle, slant, pixelSize, encoding);
                TRY_LOAD;
            }

            /* try 3 */
            jio_snprintf(buffer2, sizeof(buffer2),
                         "-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",
                         style, slant, pixelSize, encoding);
            TRY_LOAD;
            if (altstyle != NULL) {
                jio_snprintf(buffer2, sizeof(buffer2),
                             "-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",
                             altstyle, slant, pixelSize, encoding);
                TRY_LOAD;
            }

            /* try 4 */
            jio_snprintf(buffer2, sizeof(buffer2),
                         "-*-*-*-%s-*-*-%d-*-*-*-*-*-%s",
                         slant, pixelSize, encoding);

            TRY_LOAD;

            /* try 5. */
            jio_snprintf(buffer2, sizeof(buffer2),
                         "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
                         pixelSize, encoding);
            TRY_LOAD;

            /* try 6. */
            for (i = 1; i < 4; i++) {
                if (pixelSize < i)
                    break;
                jio_snprintf(buffer2, sizeof(buffer2),
                             "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
                             family, style, slant, pixelSize + i, encoding);
                TRY_LOAD;

                jio_snprintf(buffer2, sizeof(buffer2),
                             "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
                             family, style, slant, pixelSize - i, encoding);
                TRY_LOAD;

                jio_snprintf(buffer2, sizeof(buffer2),
                             "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
                             pixelSize + i, encoding);
                TRY_LOAD;

                jio_snprintf(buffer2, sizeof(buffer2),
                             "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
                             pixelSize - i, encoding);
                TRY_LOAD;
            }
        }
    }

    strcpy(name, defaultXLFD);
    return XLoadQueryFont(display, defaultXLFD);
}

/*
 * Hardwired list of mappings for generic font names "Helvetica",
 * "TimesRoman", "Courier", "Dialog", and "DialogInput".
 */
static char *defaultfontname = "fixed";
static char *defaultfoundry = "misc";
static char *anyfoundry = "*";
static char *anystyle = "*-*";
static char *isolatin1 = "iso8859-1";

static char *
Style(int32_t s)
{
    switch (s) {
        case java_awt_Font_ITALIC:
            return "medium-i";
        case java_awt_Font_BOLD:
            return "bold-r";
        case java_awt_Font_BOLD + java_awt_Font_ITALIC:
            return "bold-i";
        case java_awt_Font_PLAIN:
        default:
            return "medium-r";
    }
}

static int32_t
awtJNI_FontName(JNIEnv * env, jstring name, char **foundry, char **facename, char **encoding)
{
    char *cname = NULL;

    if (JNU_IsNull(env, name)) {
        return 0;
    }
    cname = (char *) JNU_GetStringPlatformChars(env, name, NULL);
    if (cname == NULL) {
        (*env)->ExceptionClear(env);
        JNU_ThrowOutOfMemoryError(env, "Could not create font name");
        return 0;
    }

    /* additional default font names */
    if (strcmp(cname, "serif") == 0) {
        *foundry = "adobe";
        *facename = "times";
        *encoding = isolatin1;
    } else if (strcmp(cname, "sansserif") == 0) {
        *foundry = "adobe";
        *facename = "helvetica";
        *encoding = isolatin1;
    } else if (strcmp(cname, "monospaced") == 0) {
        *foundry = "adobe";
        *facename = "courier";
        *encoding = isolatin1;
    } else if (strcmp(cname, "helvetica") == 0) {
        *foundry = "adobe";
        *facename = "helvetica";
        *encoding = isolatin1;
    } else if (strcmp(cname, "timesroman") == 0) {
        *foundry = "adobe";
        *facename = "times";
        *encoding = isolatin1;
    } else if (strcmp(cname, "courier") == 0) {
        *foundry = "adobe";
        *facename = "courier";
        *encoding = isolatin1;
    } else if (strcmp(cname, "dialog") == 0) {
        *foundry = "b&h";
        *facename = "lucida";
        *encoding = isolatin1;
    } else if (strcmp(cname, "dialoginput") == 0) {
        *foundry = "b&h";
        *facename = "lucidatypewriter";
        *encoding = isolatin1;
    } else if (strcmp(cname, "zapfdingbats") == 0) {
        *foundry = "itc";
        *facename = "zapfdingbats";
        *encoding = "*-*";
    } else {
#ifdef DEBUG
        jio_fprintf(stderr, "Unknown font: %s\n", cname);
#endif
        *foundry = defaultfoundry;
        *facename = defaultfontname;
        *encoding = isolatin1;
    }

    if (cname != NULL)
        JNU_ReleaseStringPlatformChars(env, name, (const char *) cname);

    return 1;
}

/*
 * Registered with the 2D disposer to be called after the Font is GC'd.
 */
static void pDataDisposeMethod(JNIEnv *env, jlong pData)
{
    struct FontData *fdata = NULL;
    int32_t i = 0;
    Display *display = XDISPLAY;

    AWT_LOCK();
    fdata = (struct FontData *)pData;

    if (fdata == NULL) {
        AWT_UNLOCK();
        return;
    }

    if (fdata->xfs != NULL) {
        XFreeFontSet(display, fdata->xfs);
    }

    /* AWT fonts are always "multifonts" and probably have been in
     * all post 1.0 releases, so this test for multi fonts is
     * probably not needed, and the singleton xfont is probably never used.
     */
    if (fdata->charset_num > 0) {
        for (i = 0; i < fdata->charset_num; i++) {
            free((void *)fdata->flist[i].xlfd);
            JNU_ReleaseStringPlatformChars(env, NULL,
                                           fdata->flist[i].charset_name);
            if (fdata->flist[i].load) {
                XFreeFont(display, fdata->flist[i].xfont);
            }
        }

        free((void *)fdata->flist);

        /* Don't free fdata->xfont because it is equal to fdata->flist[i].xfont
           for some 'i' */
    } else {
        if (fdata->xfont != NULL) {
            XFreeFont(display, fdata->xfont);
        }
    }

    free((void *)fdata);

    AWT_UNLOCK();
}
#endif /* !HEADLESS */