blob: adf85d4fa404a960923bb5b4e93d66573fabf438 [file] [log] [blame]
/*
* Copyright (c) 1996, 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.
*/
/*
* These routines are used for display string with multi font.
*/
#ifdef HEADLESS
#error This file should not be included in headless library
#endif
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <jni.h>
#include <jni_util.h>
#include <jvm.h>
#include "awt_Font.h"
#include "awt_p.h"
#include "multi_font.h"
extern XFontStruct *loadFont(Display *, char *, int32_t);
extern struct FontIDs fontIDs;
extern struct PlatformFontIDs platformFontIDs;
extern struct XFontPeerIDs xFontPeerIDs;
/*
* make string with str + string representation of num
* This string is used as tag string of Motif Compound String and FontList.
*/
static void
makeTag(char *str, int32_t num, char *buf)
{
int32_t len = strlen(str);
strcpy(buf, str);
buf[len] = '0' + num % 100;
buf[len + 1] = '\0';
}
static int32_t
awtJNI_GetFontDescriptorNumber(JNIEnv * env
,jobject font
,jobject fd)
{
int32_t i = 0, num;
/* initialize to NULL so that DeleteLocalRef will work. */
jobjectArray componentFonts = NULL;
jobject peer = NULL;
jobject temp = NULL;
jboolean validRet = JNI_FALSE;
if ((*env)->EnsureLocalCapacity(env, 2) < 0 || (*env)->ExceptionCheck(env))
goto done;
peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
if (peer == NULL)
goto done;
componentFonts = (jobjectArray)
(*env)->GetObjectField(env,peer,platformFontIDs.componentFonts);
if (componentFonts == NULL)
goto done;
num = (*env)->GetArrayLength(env, componentFonts);
for (i = 0; i < num; i++) {
temp = (*env)->GetObjectArrayElement(env, componentFonts, i);
if ((*env)->IsSameObject(env, fd, temp)) {
validRet = JNI_TRUE;
break;
}
(*env)->DeleteLocalRef(env, temp);
}
done:
(*env)->DeleteLocalRef(env, peer);
(*env)->DeleteLocalRef(env, componentFonts);
if (validRet)
return i;
return 0;
}
jobject
awtJNI_GetFMFont(JNIEnv * env, jobject this)
{
return JNU_CallMethodByName(env, NULL, this, "getFont_NoClientCode",
"()Ljava/awt/Font;").l;
}
jboolean
awtJNI_IsMultiFont(JNIEnv * env, jobject this)
{
jobject peer = NULL;
jobject fontConfig = NULL;
if (this == NULL) {
return JNI_FALSE;
}
if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
return JNI_FALSE;
}
peer = (*env)->CallObjectMethod(env,this,fontIDs.getPeer);
if (peer == NULL) {
return JNI_FALSE;
}
fontConfig = (*env)->GetObjectField(env,peer,platformFontIDs.fontConfig);
(*env)->DeleteLocalRef(env, peer);
if (fontConfig == NULL) {
return JNI_FALSE;
}
(*env)->DeleteLocalRef(env, fontConfig);
return JNI_TRUE;
}
jboolean
awtJNI_IsMultiFontMetrics(JNIEnv * env, jobject this)
{
jobject peer = NULL;
jobject fontConfig = NULL;
jobject font = NULL;
if (JNU_IsNull(env, this)) {
return JNI_FALSE;
}
if ((*env)->EnsureLocalCapacity(env, 3) < 0) {
return JNI_FALSE;
}
font = JNU_CallMethodByName(env, NULL, this, "getFont_NoClientCode",
"()Ljava/awt/Font;").l;
if (JNU_IsNull(env, font) || (*env)->ExceptionCheck(env)) {
return JNI_FALSE;
}
peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
(*env)->DeleteLocalRef(env, font);
if (peer == NULL) {
return JNI_FALSE;
}
fontConfig = (*env)->GetObjectField(env,peer,platformFontIDs.fontConfig);
(*env)->DeleteLocalRef(env, peer);
if (fontConfig == NULL) {
return JNI_FALSE;
}
(*env)->DeleteLocalRef(env, fontConfig);
return JNI_TRUE;
}
/* #define FONT_DEBUG 2 */
XFontSet
awtJNI_MakeFontSet(JNIEnv * env, jobject font)
{
jstring xlfd = NULL;
char *xfontset = NULL;
int32_t size;
int32_t length = 0;
char *realxlfd = NULL, *ptr = NULL, *prev = NULL;
char **missing_list = NULL;
int32_t missing_count;
char *def_string = NULL;
XFontSet xfs;
jobject peer = NULL;
jstring xfsname = NULL;
#ifdef FONT_DEBUG
char xx[1024];
#endif
if ((*env)->EnsureLocalCapacity(env, 2) < 0)
return 0;
size = (*env)->GetIntField(env, font, fontIDs.size) * 10;
peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
xfsname = (*env)->GetObjectField(env, peer, xFontPeerIDs.xfsname);
if (JNU_IsNull(env, xfsname))
xfontset = "";
else
xfontset = (char *)JNU_GetStringPlatformChars(env, xfsname, NULL);
realxlfd = malloc(strlen(xfontset) + 50);
prev = ptr = xfontset;
while ((ptr = strstr(ptr, "%d"))) {
char save = *(ptr + 2);
*(ptr + 2) = '\0';
jio_snprintf(realxlfd + length, strlen(xfontset) + 50 - length,
prev, size);
length = strlen(realxlfd);
*(ptr + 2) = save;
prev = ptr + 2;
ptr += 2;
}
strcpy(realxlfd + length, prev);
#ifdef FONT_DEBUG
strcpy(xx, realxlfd);
#endif
xfs = XCreateFontSet(awt_display, realxlfd, &missing_list,
&missing_count, &def_string);
#if FONT_DEBUG >= 2
fprintf(stderr, "XCreateFontSet(%s)->0x%x\n", xx, xfs);
#endif
#if FONT_DEBUG
if (missing_count != 0) {
int32_t i;
fprintf(stderr, "XCreateFontSet missing %d fonts:\n", missing_count);
for (i = 0; i < missing_count; ++i) {
fprintf(stderr, "\t\"%s\"\n", missing_list[i]);
}
fprintf(stderr, " requested \"%s\"\n", xx);
#if FONT_DEBUG >= 3
exit(-1);
#endif
}
#endif
free((void *)realxlfd);
if (xfontset && !JNU_IsNull(env, xfsname))
JNU_ReleaseStringPlatformChars(env, xfsname, (const char *) xfontset);
(*env)->DeleteLocalRef(env, peer);
(*env)->DeleteLocalRef(env, xfsname);
return xfs;
}
/*
* get multi font string width with multiple X11 font
*
* ASSUMES: We are not running on a privileged thread
*/
int32_t
awtJNI_GetMFStringWidth(JNIEnv * env, jcharArray s, int offset, int sLength, jobject font)
{
char *err = NULL;
unsigned char *stringData = NULL;
char *offsetStringData = NULL;
int32_t stringCount, i;
int32_t size;
struct FontData *fdata = NULL;
jobject fontDescriptor = NULL;
jbyteArray data = NULL;
int32_t j;
int32_t width = 0;
int32_t length;
XFontStruct *xf = NULL;
jobjectArray dataArray = NULL;
if ((*env)->EnsureLocalCapacity(env, 3) < 0)
return 0;
if (!JNU_IsNull(env, s) && !JNU_IsNull(env, font))
{
jobject peer;
peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
dataArray = (*env)->CallObjectMethod(
env,
peer,
platformFontIDs.makeConvertedMultiFontChars,
s, offset, sLength);
if ((*env)->ExceptionOccurred(env))
{
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
(*env)->DeleteLocalRef(env, peer);
if(dataArray == NULL)
{
return 0;
}
} else {
return 0;
}
fdata = awtJNI_GetFontData(env, font, &err);
if ((*env)->ExceptionCheck(env)) {
(*env)->DeleteLocalRef(env, dataArray);
return 0;
}
stringCount = (*env)->GetArrayLength(env, dataArray);
size = (*env)->GetIntField(env, font, fontIDs.size);
for (i = 0; i < stringCount; i+=2)
{
fontDescriptor = (*env)->GetObjectArrayElement(env, dataArray, i);
data = (*env)->GetObjectArrayElement(env, dataArray, i + 1);
/* Bail if we've finished */
if (fontDescriptor == NULL || data == NULL) {
(*env)->DeleteLocalRef(env, fontDescriptor);
(*env)->DeleteLocalRef(env, data);
break;
}
j = awtJNI_GetFontDescriptorNumber(env, font, fontDescriptor);
if ((*env)->ExceptionCheck(env)) {
(*env)->DeleteLocalRef(env, fontDescriptor);
(*env)->DeleteLocalRef(env, data);
break;
}
if (fdata->flist[j].load == 0) {
xf = loadFont(awt_display,
fdata->flist[j].xlfd, size * 10);
if (xf == NULL) {
(*env)->DeleteLocalRef(env, fontDescriptor);
(*env)->DeleteLocalRef(env, data);
continue;
}
fdata->flist[j].load = 1;
fdata->flist[j].xfont = xf;
if (xf->min_byte1 == 0 && xf->max_byte1 == 0)
fdata->flist[j].index_length = 1;
else
fdata->flist[j].index_length = 2;
}
xf = fdata->flist[j].xfont;
stringData =
(unsigned char *)(*env)->GetPrimitiveArrayCritical(env, data,NULL);
if (stringData == NULL) {
(*env)->DeleteLocalRef(env, fontDescriptor);
(*env)->DeleteLocalRef(env, data);
(*env)->ExceptionClear(env);
JNU_ThrowOutOfMemoryError(env, "Could not get string data");
break;
}
length = (stringData[0] << 24) | (stringData[1] << 16) |
(stringData[2] << 8) | stringData[3];
offsetStringData = (char *)(stringData + (4 * sizeof(char)));
if (fdata->flist[j].index_length == 2) {
width += XTextWidth16(xf, (XChar2b *)offsetStringData, length/2);
} else {
width += XTextWidth(xf, offsetStringData, length);
}
(*env)->ReleasePrimitiveArrayCritical(env, data, stringData, JNI_ABORT);
(*env)->DeleteLocalRef(env, fontDescriptor);
(*env)->DeleteLocalRef(env, data);
}
(*env)->DeleteLocalRef(env, dataArray);
return width;
}