/*
* 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 */