Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/sun/awt/awt_Font.c
32287 views
/*1* Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#ifndef HEADLESS2627#include "awt_p.h"28#include <string.h>29#include "java_awt_Component.h"30#include "java_awt_Font.h"31#include "java_awt_FontMetrics.h"32#include "sun_awt_X11GraphicsEnvironment.h"3334#include "awt_Font.h"3536#include "java_awt_Dimension.h"37#include "multi_font.h"38#include "Disposer.h"39#endif /* !HEADLESS */40#include <jni.h>41#ifndef HEADLESS42#include <jni_util.h>4344#define defaultXLFD "-*-helvetica-*-*-*-*-12-*-*-*-*-*-iso8859-1"4546struct FontIDs fontIDs;47struct PlatformFontIDs platformFontIDs;4849static void pDataDisposeMethod(JNIEnv *env, jlong pData);5051/* #define FONT_DEBUG 2 */52/* 1- print failures, 2- print all, 3- terminate on failure */53#if FONT_DEBUG54static XFontStruct *XLoadQueryFontX(Display *display, char *name)55{56XFontStruct *result = NULL;57result = XLoadQueryFont(display, name);58#if FONT_DEBUG < 259if (result == NULL)60#endif61fprintf(stderr, "XLoadQueryFont(\"%s\") -> 0x%x.\n", name, result);62#if FONT_DEBUG >= 363if (result == NULL)64exit(-1);65#endif66return result;67}68#define XLoadQueryFont XLoadQueryFontX69#endif70#endif /* !HEADLESS */7172/*73* Class: java_awt_Font74* Method: initIDs75* Signature: ()V76*/7778/* This function gets called from the static initializer for Font.java79to initialize the fieldIDs for fields that may be accessed from C */8081JNIEXPORT void JNICALL82Java_java_awt_Font_initIDs83(JNIEnv *env, jclass cls)84{85#ifndef HEADLESS86/** We call "NoClientCode" methods because they won't invoke client87code on the privileged toolkit thread **/88CHECK_NULL(fontIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"));89CHECK_NULL(fontIDs.style = (*env)->GetFieldID(env, cls, "style", "I"));90CHECK_NULL(fontIDs.size = (*env)->GetFieldID(env, cls, "size", "I"));91CHECK_NULL(fontIDs.getPeer = (*env)->GetMethodID(env, cls, "getPeer_NoClientCode",92"()Ljava/awt/peer/FontPeer;"));93CHECK_NULL(fontIDs.getFamily = (*env)->GetMethodID(env, cls, "getFamily_NoClientCode",94"()Ljava/lang/String;"));95#endif /* !HEADLESS */96}9798#ifndef HEADLESS99/* fieldIDs for FontDescriptor fields that may be accessed from C */100static struct FontDescriptorIDs {101jfieldID nativeName;102jfieldID charsetName;103} fontDescriptorIDs;104#endif /* !HEADLESS */105106/*107* Class: sun_awt_FontDescriptor108* Method: initIDs109* Signature: ()V110*/111112/* This function gets called from the static initializer for113FontDescriptor.java to initialize the fieldIDs for fields114that may be accessed from C */115116JNIEXPORT void JNICALL117Java_sun_awt_FontDescriptor_initIDs118(JNIEnv *env, jclass cls)119{120#ifndef HEADLESS121CHECK_NULL(fontDescriptorIDs.nativeName =122(*env)->GetFieldID(env, cls, "nativeName", "Ljava/lang/String;"));123CHECK_NULL(fontDescriptorIDs.charsetName =124(*env)->GetFieldID(env, cls, "charsetName", "Ljava/lang/String;"));125#endif /* !HEADLESS */126}127128/*129* Class: sun_awt_PlatformFont130* Method: initIDs131* Signature: ()V132*/133134/* This function gets called from the static initializer for135PlatformFont.java to initialize the fieldIDs for fields136that may be accessed from C */137138JNIEXPORT void JNICALL139Java_sun_awt_PlatformFont_initIDs140(JNIEnv *env, jclass cls)141{142#ifndef HEADLESS143CHECK_NULL(platformFontIDs.componentFonts =144(*env)->GetFieldID(env, cls, "componentFonts",145"[Lsun/awt/FontDescriptor;"));146CHECK_NULL(platformFontIDs.fontConfig =147(*env)->GetFieldID(env,cls, "fontConfig",148"Lsun/awt/FontConfiguration;"));149CHECK_NULL(platformFontIDs.makeConvertedMultiFontString =150(*env)->GetMethodID(env, cls, "makeConvertedMultiFontString",151"(Ljava/lang/String;)[Ljava/lang/Object;"));152CHECK_NULL(platformFontIDs.makeConvertedMultiFontChars =153(*env)->GetMethodID(env, cls, "makeConvertedMultiFontChars",154"([CII)[Ljava/lang/Object;"));155#endif /* !HEADLESS */156}157158#ifndef HEADLESS159XFontStruct *160loadFont(Display * display, char *name, int32_t pointSize)161{162XFontStruct *f = NULL;163164/* try the exact xlfd name in font configuration file */165f = XLoadQueryFont(display, name);166if (f != NULL) {167return f;168}169170/*171* try nearly font172*173* 1. specify FAMILY_NAME, WEIGHT_NAME, SLANT, POINT_SIZE,174* CHARSET_REGISTRY and CHARSET_ENCODING.175* 2. change POINT_SIZE to PIXEL_SIZE176* 3. change FAMILY_NAME to *177* 4. specify only PIXEL_SIZE and CHARSET_REGISTRY/ENCODING178* 5. change PIXEL_SIZE +1/-1/+2/-2...+4/-4179* 6. default font pattern180*/181{182/*183* This code assumes the name contains exactly 14 '-' delimiter.184* If not use default pattern.185*/186int32_t i, length, pixelSize;187Boolean useDefault = FALSE;188189char buffer[BUFSIZ], buffer2[BUFSIZ];190char *family = NULL, *style = NULL, *slant = NULL, *encoding = NULL;191char *start = NULL, *end = NULL;192193if (strlen(name) > BUFSIZ - 1) {194useDefault = TRUE;195} else {196strcpy(buffer, name);197}198199#define NEXT_HYPHEN\200start = end + 1;\201end = strchr(start, '-');\202if (end == NULL) {\203useDefault = TRUE;\204break;\205}\206*end = '\0'207208do {209end = buffer;210211/* skip FOUNDRY */212NEXT_HYPHEN;213214/* set FAMILY_NAME */215NEXT_HYPHEN;216family = start;217218/* set STYLE_NAME */219NEXT_HYPHEN;220style = start;221222/* set SLANT */223NEXT_HYPHEN;224slant = start;225226/* skip SETWIDTH_NAME, ADD_STYLE_NAME, PIXEL_SIZE227POINT_SIZE, RESOLUTION_X, RESOLUTION_Y, SPACING228and AVERAGE_WIDTH */229NEXT_HYPHEN;230NEXT_HYPHEN;231NEXT_HYPHEN;232NEXT_HYPHEN;233NEXT_HYPHEN;234NEXT_HYPHEN;235NEXT_HYPHEN;236NEXT_HYPHEN;237238/* set CHARSET_REGISTRY and CHARSET_ENCODING */239encoding = end + 1;240}241while (0);242243#define TRY_LOAD\244f = XLoadQueryFont(display, buffer2);\245if (f != NULL) {\246strcpy(name, buffer2);\247return f;\248}249250if (!useDefault) {251char *altstyle = NULL;252253/* Regular is the style for TrueType fonts -- Type1, F3 use roman */254if (strcmp(style, "regular") == 0) {255altstyle = "roman";256}257#if defined(__linux__) || defined(MACOSX)258if (!strcmp(family, "lucidasans")) {259family = "lucida";260}261#endif262/* try 1. */263jio_snprintf(buffer2, sizeof(buffer2),264"-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",265family, style, slant, pointSize, encoding);266TRY_LOAD;267268if (altstyle != NULL) {269jio_snprintf(buffer2, sizeof(buffer2),270"-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",271family, altstyle, slant, pointSize, encoding);272TRY_LOAD;273}274275/* search bitmap font */276pixelSize = pointSize / 10;277278/* try 2. */279jio_snprintf(buffer2, sizeof(buffer2),280"-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",281family, style, slant, pixelSize, encoding);282TRY_LOAD;283284if (altstyle != NULL) {285jio_snprintf(buffer2, sizeof(buffer2),286"-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",287family, altstyle, slant, pixelSize, encoding);288TRY_LOAD;289}290291/* try 3 */292jio_snprintf(buffer2, sizeof(buffer2),293"-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",294style, slant, pixelSize, encoding);295TRY_LOAD;296if (altstyle != NULL) {297jio_snprintf(buffer2, sizeof(buffer2),298"-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",299altstyle, slant, pixelSize, encoding);300TRY_LOAD;301}302303/* try 4 */304jio_snprintf(buffer2, sizeof(buffer2),305"-*-*-*-%s-*-*-%d-*-*-*-*-*-%s",306slant, pixelSize, encoding);307308TRY_LOAD;309310/* try 5. */311jio_snprintf(buffer2, sizeof(buffer2),312"-*-*-*-*-*-*-%d-*-*-*-*-*-%s",313pixelSize, encoding);314TRY_LOAD;315316/* try 6. */317for (i = 1; i < 4; i++) {318if (pixelSize < i)319break;320jio_snprintf(buffer2, sizeof(buffer2),321"-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",322family, style, slant, pixelSize + i, encoding);323TRY_LOAD;324325jio_snprintf(buffer2, sizeof(buffer2),326"-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",327family, style, slant, pixelSize - i, encoding);328TRY_LOAD;329330jio_snprintf(buffer2, sizeof(buffer2),331"-*-*-*-*-*-*-%d-*-*-*-*-*-%s",332pixelSize + i, encoding);333TRY_LOAD;334335jio_snprintf(buffer2, sizeof(buffer2),336"-*-*-*-*-*-*-%d-*-*-*-*-*-%s",337pixelSize - i, encoding);338TRY_LOAD;339}340}341}342343strcpy(name, defaultXLFD);344return XLoadQueryFont(display, defaultXLFD);345}346347/*348* Hardwired list of mappings for generic font names "Helvetica",349* "TimesRoman", "Courier", "Dialog", and "DialogInput".350*/351static char *defaultfontname = "fixed";352static char *defaultfoundry = "misc";353static char *anyfoundry = "*";354static char *anystyle = "*-*";355static char *isolatin1 = "iso8859-1";356357static char *358Style(int32_t s)359{360switch (s) {361case java_awt_Font_ITALIC:362return "medium-i";363case java_awt_Font_BOLD:364return "bold-r";365case java_awt_Font_BOLD + java_awt_Font_ITALIC:366return "bold-i";367case java_awt_Font_PLAIN:368default:369return "medium-r";370}371}372373static int32_t374awtJNI_FontName(JNIEnv * env, jstring name, char **foundry, char **facename, char **encoding)375{376char *cname = NULL;377378if (JNU_IsNull(env, name)) {379return 0;380}381cname = (char *) JNU_GetStringPlatformChars(env, name, NULL);382if (cname == NULL) {383(*env)->ExceptionClear(env);384JNU_ThrowOutOfMemoryError(env, "Could not create font name");385return 0;386}387388/* additional default font names */389if (strcmp(cname, "serif") == 0) {390*foundry = "adobe";391*facename = "times";392*encoding = isolatin1;393} else if (strcmp(cname, "sansserif") == 0) {394*foundry = "adobe";395*facename = "helvetica";396*encoding = isolatin1;397} else if (strcmp(cname, "monospaced") == 0) {398*foundry = "adobe";399*facename = "courier";400*encoding = isolatin1;401} else if (strcmp(cname, "helvetica") == 0) {402*foundry = "adobe";403*facename = "helvetica";404*encoding = isolatin1;405} else if (strcmp(cname, "timesroman") == 0) {406*foundry = "adobe";407*facename = "times";408*encoding = isolatin1;409} else if (strcmp(cname, "courier") == 0) {410*foundry = "adobe";411*facename = "courier";412*encoding = isolatin1;413} else if (strcmp(cname, "dialog") == 0) {414*foundry = "b&h";415*facename = "lucida";416*encoding = isolatin1;417} else if (strcmp(cname, "dialoginput") == 0) {418*foundry = "b&h";419*facename = "lucidatypewriter";420*encoding = isolatin1;421} else if (strcmp(cname, "zapfdingbats") == 0) {422*foundry = "itc";423*facename = "zapfdingbats";424*encoding = "*-*";425} else {426#ifdef DEBUG427jio_fprintf(stderr, "Unknown font: %s\n", cname);428#endif429*foundry = defaultfoundry;430*facename = defaultfontname;431*encoding = isolatin1;432}433434if (cname != NULL)435JNU_ReleaseStringPlatformChars(env, name, (const char *) cname);436437return 1;438}439440struct FontData *441awtJNI_GetFontData(JNIEnv * env, jobject font, char **errmsg)442{443/* We are going to create at most 4 outstanding local refs in this444* function. */445if ((*env)->EnsureLocalCapacity(env, 4) < 0) {446return NULL;447}448449if (!JNU_IsNull(env, font) && awtJNI_IsMultiFont(env, font)) {450JNU_CHECK_EXCEPTION_RETURN(env, NULL);451452struct FontData *fdata = NULL;453int32_t i, size;454char *fontsetname = NULL;455char *nativename = NULL;456jobjectArray componentFonts = NULL;457jobject peer = NULL;458jobject fontDescriptor = NULL;459jstring fontDescriptorName = NULL;460jstring charsetName = NULL;461462fdata = (struct FontData *) JNU_GetLongFieldAsPtr(env,font,463fontIDs.pData);464465if (fdata != NULL && fdata->flist != NULL) {466return fdata;467}468size = (*env)->GetIntField(env, font, fontIDs.size);469fdata = (struct FontData *) malloc(sizeof(struct FontData));470471peer = (*env)->CallObjectMethod(env, font, fontIDs.getPeer);472473componentFonts =474(*env)->GetObjectField(env, peer, platformFontIDs.componentFonts);475/* We no longer need peer */476(*env)->DeleteLocalRef(env, peer);477478fdata->charset_num = (*env)->GetArrayLength(env, componentFonts);479480fdata->flist = (awtFontList *) malloc(sizeof(awtFontList)481* fdata->charset_num);482fdata->xfont = NULL;483for (i = 0; i < fdata->charset_num; i++) {484/*485* set xlfd name486*/487488fontDescriptor = (*env)->GetObjectArrayElement(env, componentFonts, i);489fontDescriptorName =490(*env)->GetObjectField(env, fontDescriptor,491fontDescriptorIDs.nativeName);492493if (!JNU_IsNull(env, fontDescriptorName)) {494nativename = (char *) JNU_GetStringPlatformChars(env, fontDescriptorName, NULL);495} else {496nativename = "";497}498499fdata->flist[i].xlfd = malloc(strlen(nativename)500+ strlen(defaultXLFD));501jio_snprintf(fdata->flist[i].xlfd, strlen(nativename) + 10,502nativename, size * 10);503504if (nativename != NULL && nativename != "")505JNU_ReleaseStringPlatformChars(env, fontDescriptorName, (const char *) nativename);506507/*508* set charset_name509*/510511charsetName =512(*env)->GetObjectField(env, fontDescriptor,513fontDescriptorIDs.charsetName);514515fdata->flist[i].charset_name = (char *)516JNU_GetStringPlatformChars(env, charsetName, NULL);517if (fdata->flist[i].charset_name == NULL) {518(*env)->ExceptionClear(env);519JNU_ThrowOutOfMemoryError(env, "Could not create charset name");520return NULL;521}522523/* We are done with the objects. */524(*env)->DeleteLocalRef(env, fontDescriptor);525(*env)->DeleteLocalRef(env, fontDescriptorName);526(*env)->DeleteLocalRef(env, charsetName);527528/*529* set load & XFontStruct530*/531fdata->flist[i].load = 0;532533/*534* This appears to be a bogus check. The actual intent appears535* to be to find out whether this is the "base" font in a set,536* rather than iso8859_1 explicitly. Note that iso8859_15 will537* and must also pass this test.538*/539540if (fdata->xfont == NULL &&541strstr(fdata->flist[i].charset_name, "8859_1")) {542fdata->flist[i].xfont =543loadFont(awt_display, fdata->flist[i].xlfd, size * 10);544if (fdata->flist[i].xfont != NULL) {545fdata->flist[i].load = 1;546fdata->xfont = fdata->flist[i].xfont;547fdata->flist[i].index_length = 1;548} else {549/* Free any already allocated storage and fonts */550int j = i;551for (j = 0; j <= i; j++) {552free((void *)fdata->flist[j].xlfd);553JNU_ReleaseStringPlatformChars(env, NULL,554fdata->flist[j].charset_name);555if (fdata->flist[j].load) {556XFreeFont(awt_display, fdata->flist[j].xfont);557}558}559free((void *)fdata->flist);560free((void *)fdata);561562if (errmsg != NULL) {563*errmsg = "java/lang" "NullPointerException";564}565(*env)->DeleteLocalRef(env, componentFonts);566return NULL;567}568}569}570(*env)->DeleteLocalRef(env, componentFonts);571/*572* XFontSet will create if the peer of TextField/TextArea573* are used.574*/575fdata->xfs = NULL;576577JNU_SetLongFieldFromPtr(env,font,fontIDs.pData,fdata);578Disposer_AddRecord(env, font, pDataDisposeMethod, ptr_to_jlong(fdata));579return fdata;580} else {581JNU_CHECK_EXCEPTION_RETURN(env, NULL);582Display *display = NULL;583struct FontData *fdata = NULL;584char fontSpec[1024];585int32_t height;586int32_t oheight;587int32_t above = 0; /* tries above height */588int32_t below = 0; /* tries below height */589char *foundry = NULL;590char *name = NULL;591char *encoding = NULL;592char *style = NULL;593XFontStruct *xfont = NULL;594jstring family = NULL;595596if (JNU_IsNull(env, font)) {597if (errmsg != NULL) {598*errmsg = "java/lang" "NullPointerException";599}600return (struct FontData *) NULL;601}602display = XDISPLAY;603604fdata = (struct FontData *) JNU_GetLongFieldAsPtr(env,font,fontIDs.pData);605if (fdata != NULL && fdata->xfont != NULL) {606return fdata;607}608609family = (*env)->CallObjectMethod(env, font, fontIDs.getFamily);610611if (!awtJNI_FontName(env, family, &foundry, &name, &encoding)) {612if (errmsg != NULL) {613*errmsg = "java/lang" "NullPointerException";614}615(*env)->DeleteLocalRef(env, family);616return (struct FontData *) NULL;617}618style = Style((*env)->GetIntField(env, font, fontIDs.style));619oheight = height = (*env)->GetIntField(env, font, fontIDs.size);620621while (1) {622jio_snprintf(fontSpec, sizeof(fontSpec), "-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",623foundry,624name,625style,626height,627encoding);628629/*fprintf(stderr,"LoadFont: %s\n", fontSpec); */630xfont = XLoadQueryFont(display, fontSpec);631632/* XXX: sometimes XLoadQueryFont returns a bogus font structure */633/* with negative ascent. */634if (xfont == (Font) NULL || xfont->ascent < 0) {635if (xfont != NULL) {636XFreeFont(display, xfont);637}638if (foundry != anyfoundry) { /* Use ptr comparison here, not strcmp */639/* Try any other foundry before messing with the sizes */640foundry = anyfoundry;641continue;642}643/* We couldn't find the font. We'll try to find an */644/* alternate by searching for heights above and below our */645/* preferred height. We try for 4 heights above and below. */646/* If we still can't find a font we repeat the algorithm */647/* using misc-fixed as the font. If we then fail, then we */648/* give up and signal an error. */649if (above == below) {650above++;651height = oheight + above;652} else {653below++;654if (below > 4) {655if (name != defaultfontname || style != anystyle) {656name = defaultfontname;657foundry = defaultfoundry;658height = oheight;659style = anystyle;660encoding = isolatin1;661above = below = 0;662continue;663} else {664if (errmsg != NULL) {665*errmsg = "java/io/" "FileNotFoundException";666}667(*env)->DeleteLocalRef(env, family);668return (struct FontData *) NULL;669}670}671height = oheight - below;672}673continue;674} else {675fdata = ZALLOC(FontData);676677if (fdata == NULL) {678if (errmsg != NULL) {679*errmsg = "java/lang" "OutOfMemoryError";680}681} else {682fdata->xfont = xfont;683JNU_SetLongFieldFromPtr(env,font,fontIDs.pData,fdata);684Disposer_AddRecord(env, font, pDataDisposeMethod,685ptr_to_jlong(fdata));686}687(*env)->DeleteLocalRef(env, family);688return fdata;689}690}691/* not reached */692}693}694695/*696* Registered with the 2D disposer to be called after the Font is GC'd.697*/698static void pDataDisposeMethod(JNIEnv *env, jlong pData)699{700struct FontData *fdata = NULL;701int32_t i = 0;702Display *display = XDISPLAY;703704AWT_LOCK();705fdata = (struct FontData *)pData;706707if (fdata == NULL) {708AWT_UNLOCK();709return;710}711712if (fdata->xfs != NULL) {713XFreeFontSet(display, fdata->xfs);714}715716/* AWT fonts are always "multifonts" and probably have been in717* all post 1.0 releases, so this test test for multi fonts is718* probably not needed, and the singleton xfont is probably never used.719*/720if (fdata->charset_num > 0) {721for (i = 0; i < fdata->charset_num; i++) {722free((void *)fdata->flist[i].xlfd);723JNU_ReleaseStringPlatformChars(env, NULL,724fdata->flist[i].charset_name);725if (fdata->flist[i].load) {726XFreeFont(display, fdata->flist[i].xfont);727}728}729730free((void *)fdata->flist);731732/* Don't free fdata->xfont because it is equal to fdata->flist[i].xfont733for some 'i' */734} else {735if (fdata->xfont != NULL) {736XFreeFont(display, fdata->xfont);737}738}739740free((void *)fdata);741742AWT_UNLOCK();743}744#endif /* !HEADLESS */745746747