/* * 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 #include #include #include #include #include #include #include "awt_Font.h" #include "awt_p.h" #include "multi_font.h" #ifndef FONT_DEBUG #define FONT_DEBUG 0 #endif 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; }