blob: 392dc27ac3c1e7e07e4e4dbaf7b0098df51bda1e [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26#ifndef HEADLESS
27
28#include "awt_p.h"
29#include <string.h>
30#include "java_awt_Component.h"
31#include "java_awt_Font.h"
32#include "java_awt_FontMetrics.h"
33#include "sun_awt_motif_MToolkit.h"
34#include "sun_awt_motif_X11FontMetrics.h"
35#include "sun_awt_X11GraphicsEnvironment.h"
36
37#include "awt_Font.h"
38
39#include "java_awt_Dimension.h"
40#include "multi_font.h"
41#include "Disposer.h"
42#endif /* !HEADLESS */
43#include <jni.h>
44#ifndef HEADLESS
45#include <jni_util.h>
46
47#define defaultXLFD "-*-helvetica-*-*-*-*-12-*-*-*-*-*-iso8859-1"
48
49struct FontIDs fontIDs;
50struct PlatformFontIDs platformFontIDs;
51
52static void pDataDisposeMethod(JNIEnv *env, jlong pData);
53
54/* #define FONT_DEBUG 2 */
55/* 1- print failures, 2- print all, 3- terminate on failure */
56#if FONT_DEBUG
57static XFontStruct *XLoadQueryFontX(Display *display, char *name)
58{
59 XFontStruct *result = NULL;
60 result = XLoadQueryFont(display, name);
61#if FONT_DEBUG < 2
62 if (result == NULL)
63#endif
64 fprintf(stderr, "XLoadQueryFont(\"%s\") -> 0x%x.\n", name, result);
65#if FONT_DEBUG >= 3
66 if (result == NULL)
67 exit(-1);
68#endif
69 return result;
70}
71#define XLoadQueryFont XLoadQueryFontX
72#endif
73#endif /* !HEADLESS */
74
75/*
76 * Class: java_awt_Font
77 * Method: initIDs
78 * Signature: ()V
79 */
80
81/* This function gets called from the static initializer for Font.java
82 to initialize the fieldIDs for fields that may be accessed from C */
83
84JNIEXPORT void JNICALL
85Java_java_awt_Font_initIDs
86 (JNIEnv *env, jclass cls)
87{
88#ifndef HEADLESS
89 /** We call "NoClientCode" methods because they won't invoke client
90 code on the privileged toolkit thread **/
91 fontIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");
92 fontIDs.style = (*env)->GetFieldID(env, cls, "style", "I");
93 fontIDs.size = (*env)->GetFieldID(env, cls, "size", "I");
94 fontIDs.getPeer = (*env)->GetMethodID(env, cls, "getPeer_NoClientCode",
95 "()Ljava/awt/peer/FontPeer;");
96 fontIDs.getFamily =
97 (*env)->GetMethodID(env, cls, "getFamily_NoClientCode",
98 "()Ljava/lang/String;");
99#endif /* !HEADLESS */
100}
101
102#ifndef HEADLESS
103
104/* fieldIDs for X11FontMetrics fields that may be accessed from C */
105static struct X11FontMetricsIDs {
106 jfieldID widths;
107 jfieldID font;
108 jfieldID ascent;
109 jfieldID descent;
110 jfieldID leading;
111 jfieldID height;
112 jfieldID maxAscent;
113 jfieldID maxDescent;
114 jfieldID maxHeight;
115 jfieldID maxAdvance;
116} x11FontMetricsIDs;
117
118/*
119 * Class: sun_awt_motif_X11FontMetrics
120 * Method: initIDs
121 * Signature: ()V
122 */
123
124/* This function gets called from the static initializer for
125 X11FontMetrics.java to initialize the fieldIDs for fields
126 that may be accessed from C */
127
128JNIEXPORT void JNICALL
129Java_sun_awt_motif_X11FontMetrics_initIDs
130 (JNIEnv *env, jclass cls)
131{
132 x11FontMetricsIDs.widths = (*env)->GetFieldID(env, cls, "widths", "[I");
133 x11FontMetricsIDs.font =
134 (*env)->GetFieldID(env, cls, "font", "Ljava/awt/Font;");
135 x11FontMetricsIDs.ascent =
136 (*env)->GetFieldID(env, cls, "ascent", "I");
137 x11FontMetricsIDs.descent =
138 (*env)->GetFieldID(env, cls, "descent", "I");
139 x11FontMetricsIDs.leading =
140 (*env)->GetFieldID(env, cls, "leading", "I");
141 x11FontMetricsIDs.height =
142 (*env)->GetFieldID(env, cls, "height", "I");
143 x11FontMetricsIDs.maxAscent =
144 (*env)->GetFieldID(env, cls, "maxAscent", "I");
145 x11FontMetricsIDs.maxDescent =
146 (*env)->GetFieldID(env, cls, "maxDescent", "I");
147 x11FontMetricsIDs.maxHeight =
148 (*env)->GetFieldID(env, cls, "maxHeight", "I");
149 x11FontMetricsIDs.maxAdvance =
150 (*env)->GetFieldID(env, cls, "maxAdvance", "I");
151}
152
153
154/* fieldIDs for FontDescriptor fields that may be accessed from C */
155static struct FontDescriptorIDs {
156 jfieldID nativeName;
157 jfieldID charsetName;
158} fontDescriptorIDs;
159#endif /* !HEADLESS */
160
161/*
162 * Class: sun_awt_FontDescriptor
163 * Method: initIDs
164 * Signature: ()V
165 */
166
167/* This function gets called from the static initializer for
168 FontDescriptor.java to initialize the fieldIDs for fields
169 that may be accessed from C */
170
171JNIEXPORT void JNICALL
172Java_sun_awt_FontDescriptor_initIDs
173 (JNIEnv *env, jclass cls)
174{
175#ifndef HEADLESS
176 fontDescriptorIDs.nativeName =
177 (*env)->GetFieldID(env, cls, "nativeName",
178 "Ljava/lang/String;");
179 fontDescriptorIDs.charsetName =
180 (*env)->GetFieldID(env, cls, "charsetName",
181 "Ljava/lang/String;");
182#endif /* !HEADLESS */
183}
184
185#ifndef HEADLESS
186struct MFontPeerIDs mFontPeerIDs;
187/*
188 * Class: sun_awt_motif_MFontPeer
189 * Method: initIDs
190 * Signature: ()V
191 */
192
193/* This function gets called from the static initializer for
194 MFontPeer.java to initialize the fieldIDs for fields
195 that may be accessed from C */
196
197JNIEXPORT void JNICALL
198Java_sun_awt_motif_MFontPeer_initIDs
199 (JNIEnv *env, jclass cls)
200{
201 mFontPeerIDs.xfsname =
202 (*env)->GetFieldID(env, cls, "xfsname", "Ljava/lang/String;");
203}
204#endif /* !HEADLESS */
205
206/*
207 * Class: sun_awt_PlatformFont
208 * Method: initIDs
209 * Signature: ()V
210 */
211
212/* This function gets called from the static initializer for
213 PlatformFont.java to initialize the fieldIDs for fields
214 that may be accessed from C */
215
216JNIEXPORT void JNICALL
217Java_sun_awt_PlatformFont_initIDs
218 (JNIEnv *env, jclass cls)
219{
220#ifndef HEADLESS
221 platformFontIDs.componentFonts =
222 (*env)->GetFieldID(env, cls, "componentFonts",
223 "[Lsun/awt/FontDescriptor;");
224 platformFontIDs.fontConfig =
225 (*env)->GetFieldID(env,cls, "fontConfig",
226 "Lsun/awt/FontConfiguration;");
227
228 platformFontIDs.makeConvertedMultiFontString =
229 (*env)->GetMethodID(env, cls, "makeConvertedMultiFontString",
230 "(Ljava/lang/String;)[Ljava/lang/Object;");
231
232 platformFontIDs.makeConvertedMultiFontChars =
233 (*env)->GetMethodID(env, cls, "makeConvertedMultiFontChars",
234 "([CII)[Ljava/lang/Object;");
235#endif /* !HEADLESS */
236}
237
238#ifndef HEADLESS
239XFontStruct *
240loadFont(Display * display, char *name, int32_t pointSize)
241{
242 XFontStruct *f = NULL;
243
244 /* try the exact xlfd name in font configuration file */
245 f = XLoadQueryFont(display, name);
246 if (f != NULL) {
247 return f;
248 }
249
250 /*
251 * try nearly font
252 *
253 * 1. specify FAMILY_NAME, WEIGHT_NAME, SLANT, POINT_SIZE,
254 * CHARSET_REGISTRY and CHARSET_ENCODING.
255 * 2. change POINT_SIZE to PIXEL_SIZE
256 * 3. change FAMILY_NAME to *
257 * 4. specify only PIXEL_SIZE and CHARSET_REGISTRY/ENCODING
258 * 5. change PIXEL_SIZE +1/-1/+2/-2...+4/-4
259 * 6. default font pattern
260 */
261 {
262 /*
263 * This code assumes the name contains exactly 14 '-' delimiter.
264 * If not use default pattern.
265 */
266 int32_t i, length, pixelSize;
267 Boolean useDefault = FALSE;
268
269 char buffer[BUFSIZ], buffer2[BUFSIZ];
270 char *family = NULL, *style = NULL, *slant = NULL, *encoding = NULL;
271 char *start = NULL, *end = NULL;
272
273 if (strlen(name) > BUFSIZ - 1) {
274 useDefault = TRUE;
275 } else {
276 strcpy(buffer, name);
277 }
278
279#define NEXT_HYPHEN\
280 start = end + 1;\
281 end = strchr(start, '-');\
282 if (end == NULL) {\
283 useDefault = TRUE;\
284 break;\
285 }\
286 *end = '\0'
287
288 do {
289 end = buffer;
290
291 /* skip FOUNDRY */
292 NEXT_HYPHEN;
293
294 /* set FAMILY_NAME */
295 NEXT_HYPHEN;
296 family = start;
297
298 /* set STYLE_NAME */
299 NEXT_HYPHEN;
300 style = start;
301
302 /* set SLANT */
303 NEXT_HYPHEN;
304 slant = start;
305
306 /* skip SETWIDTH_NAME, ADD_STYLE_NAME, PIXEL_SIZE
307 POINT_SIZE, RESOLUTION_X, RESOLUTION_Y, SPACING
308 and AVERAGE_WIDTH */
309 NEXT_HYPHEN;
310 NEXT_HYPHEN;
311 NEXT_HYPHEN;
312 NEXT_HYPHEN;
313 NEXT_HYPHEN;
314 NEXT_HYPHEN;
315 NEXT_HYPHEN;
316 NEXT_HYPHEN;
317
318 /* set CHARSET_REGISTRY and CHARSET_ENCODING */
319 encoding = end + 1;
320 }
321 while (0);
322
323#define TRY_LOAD\
324 f = XLoadQueryFont(display, buffer2);\
325 if (f != NULL) {\
326 strcpy(name, buffer2);\
327 return f;\
328 }
329
330 if (!useDefault) {
331 char *altstyle = NULL;
332
333 /* Regular is the style for TrueType fonts -- Type1, F3 use roman */
334 if (strcmp(style, "regular") == 0) {
335 altstyle = "roman";
336 }
337#ifdef __linux__
338 if (!strcmp(family, "lucidasans")) {
339 family = "lucida";
340 }
341#endif
342 /* try 1. */
343 jio_snprintf(buffer2, sizeof(buffer2),
344 "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",
345 family, style, slant, pointSize, encoding);
346 TRY_LOAD;
347
348 if (altstyle != NULL) {
349 jio_snprintf(buffer2, sizeof(buffer2),
350 "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",
351 family, altstyle, slant, pointSize, encoding);
352 TRY_LOAD;
353 }
354
355 /* search bitmap font */
356 pixelSize = pointSize / 10;
357
358 /* try 2. */
359 jio_snprintf(buffer2, sizeof(buffer2),
360 "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
361 family, style, slant, pixelSize, encoding);
362 TRY_LOAD;
363
364 if (altstyle != NULL) {
365 jio_snprintf(buffer2, sizeof(buffer2),
366 "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
367 family, altstyle, slant, pixelSize, encoding);
368 TRY_LOAD;
369 }
370
371 /* try 3 */
372 jio_snprintf(buffer2, sizeof(buffer2),
373 "-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",
374 style, slant, pixelSize, encoding);
375 TRY_LOAD;
376 if (altstyle != NULL) {
377 jio_snprintf(buffer2, sizeof(buffer2),
378 "-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",
379 altstyle, slant, pixelSize, encoding);
380 TRY_LOAD;
381 }
382
383 /* try 4 */
384 jio_snprintf(buffer2, sizeof(buffer2),
385 "-*-*-*-%s-*-*-%d-*-*-*-*-*-%s",
386 slant, pixelSize, encoding);
387
388 TRY_LOAD;
389
390 /* try 5. */
391 jio_snprintf(buffer2, sizeof(buffer2),
392 "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
393 pixelSize, encoding);
394 TRY_LOAD;
395
396 /* try 6. */
397 for (i = 1; i < 4; i++) {
398 if (pixelSize < i)
399 break;
400 jio_snprintf(buffer2, sizeof(buffer2),
401 "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
402 family, style, slant, pixelSize + i, encoding);
403 TRY_LOAD;
404
405 jio_snprintf(buffer2, sizeof(buffer2),
406 "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
407 family, style, slant, pixelSize - i, encoding);
408 TRY_LOAD;
409
410 jio_snprintf(buffer2, sizeof(buffer2),
411 "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
412 pixelSize + i, encoding);
413 TRY_LOAD;
414
415 jio_snprintf(buffer2, sizeof(buffer2),
416 "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
417 pixelSize - i, encoding);
418 TRY_LOAD;
419 }
420 }
421 }
422
423 strcpy(name, defaultXLFD);
424 return XLoadQueryFont(display, defaultXLFD);
425}
426
427/*
428 * Hardwired list of mappings for generic font names "Helvetica",
429 * "TimesRoman", "Courier", "Dialog", and "DialogInput".
430 */
431static char *defaultfontname = "fixed";
432static char *defaultfoundry = "misc";
433static char *anyfoundry = "*";
434static char *anystyle = "*-*";
435static char *isolatin1 = "iso8859-1";
436
437static char *
438Style(int32_t s)
439{
440 switch (s) {
441 case java_awt_Font_ITALIC:
442 return "medium-i";
443 case java_awt_Font_BOLD:
444 return "bold-r";
445 case java_awt_Font_BOLD + java_awt_Font_ITALIC:
446 return "bold-i";
447 case java_awt_Font_PLAIN:
448 default:
449 return "medium-r";
450 }
451}
452
453static int32_t
454awtJNI_FontName(JNIEnv * env, jstring name, char **foundry, char **facename, char **encoding)
455{
456 char *cname = NULL;
457
458 if (JNU_IsNull(env, name)) {
459 return 0;
460 }
461 cname = (char *) JNU_GetStringPlatformChars(env, name, NULL);
462
463 /* additional default font names */
464 if (strcmp(cname, "serif") == 0) {
465 *foundry = "adobe";
466 *facename = "times";
467 *encoding = isolatin1;
468 } else if (strcmp(cname, "sansserif") == 0) {
469 *foundry = "adobe";
470 *facename = "helvetica";
471 *encoding = isolatin1;
472 } else if (strcmp(cname, "monospaced") == 0) {
473 *foundry = "adobe";
474 *facename = "courier";
475 *encoding = isolatin1;
476 } else if (strcmp(cname, "helvetica") == 0) {
477 *foundry = "adobe";
478 *facename = "helvetica";
479 *encoding = isolatin1;
480 } else if (strcmp(cname, "timesroman") == 0) {
481 *foundry = "adobe";
482 *facename = "times";
483 *encoding = isolatin1;
484 } else if (strcmp(cname, "courier") == 0) {
485 *foundry = "adobe";
486 *facename = "courier";
487 *encoding = isolatin1;
488 } else if (strcmp(cname, "dialog") == 0) {
489 *foundry = "b&h";
490 *facename = "lucida";
491 *encoding = isolatin1;
492 } else if (strcmp(cname, "dialoginput") == 0) {
493 *foundry = "b&h";
494 *facename = "lucidatypewriter";
495 *encoding = isolatin1;
496 } else if (strcmp(cname, "zapfdingbats") == 0) {
497 *foundry = "itc";
498 *facename = "zapfdingbats";
499 *encoding = "*-*";
500 } else {
501#ifdef DEBUG
502 jio_fprintf(stderr, "Unknown font: %s\n", cname);
503#endif
504 *foundry = defaultfoundry;
505 *facename = defaultfontname;
506 *encoding = isolatin1;
507 }
508
509 if (cname != NULL)
510 JNU_ReleaseStringPlatformChars(env, name, (const char *) cname);
511
512 return 1;
513}
514
515struct FontData *
516awtJNI_GetFontData(JNIEnv * env, jobject font, char **errmsg)
517{
518 /* We are going to create at most 4 outstanding local refs in this
519 * function. */
520 if ((*env)->EnsureLocalCapacity(env, 4) < 0) {
521 return NULL;
522 }
523
524 if (!JNU_IsNull(env, font) && awtJNI_IsMultiFont(env, font)) {
525 struct FontData *fdata = NULL;
526 int32_t i, size;
527 char *fontsetname = NULL;
528 char *nativename = NULL;
529 jobjectArray componentFonts = NULL;
530 jobject peer = NULL;
531 jobject fontDescriptor = NULL;
532 jstring fontDescriptorName = NULL;
533 jstring charsetName = NULL;
534
535 fdata = (struct FontData *) JNU_GetLongFieldAsPtr(env,font,
536 fontIDs.pData);
537
538 if (fdata != NULL && fdata->flist != NULL) {
539 return fdata;
540 }
541 size = (*env)->GetIntField(env, font, fontIDs.size);
542 fdata = (struct FontData *) malloc(sizeof(struct FontData));
543
544 peer = (*env)->CallObjectMethod(env, font, fontIDs.getPeer);
545
546 componentFonts =
547 (*env)->GetObjectField(env, peer, platformFontIDs.componentFonts);
548 /* We no longer need peer */
549 (*env)->DeleteLocalRef(env, peer);
550
551 fdata->charset_num = (*env)->GetArrayLength(env, componentFonts);
552
553 fdata->flist = (awtFontList *) malloc(sizeof(awtFontList)
554 * fdata->charset_num);
555 fdata->xfont = NULL;
556 for (i = 0; i < fdata->charset_num; i++) {
557 /*
558 * set xlfd name
559 */
560
561 fontDescriptor = (*env)->GetObjectArrayElement(env, componentFonts, i);
562 fontDescriptorName =
563 (*env)->GetObjectField(env, fontDescriptor,
564 fontDescriptorIDs.nativeName);
565
566 if (!JNU_IsNull(env, fontDescriptorName)) {
567 nativename = (char *) JNU_GetStringPlatformChars(env, fontDescriptorName, NULL);
568 } else {
569 nativename = "";
570 }
571
572 fdata->flist[i].xlfd = malloc(strlen(nativename)
573 + strlen(defaultXLFD));
574 jio_snprintf(fdata->flist[i].xlfd, strlen(nativename) + 10,
575 nativename, size * 10);
576
577 if (nativename != NULL && nativename != "")
578 JNU_ReleaseStringPlatformChars(env, fontDescriptorName, (const char *) nativename);
579
580 /*
581 * set charset_name
582 */
583
584 charsetName =
585 (*env)->GetObjectField(env, fontDescriptor,
586 fontDescriptorIDs.charsetName);
587
588 fdata->flist[i].charset_name = (char *)
589 JNU_GetStringPlatformChars(env, charsetName, NULL);
590
591 /* We are done with the objects. */
592 (*env)->DeleteLocalRef(env, fontDescriptor);
593 (*env)->DeleteLocalRef(env, fontDescriptorName);
594 (*env)->DeleteLocalRef(env, charsetName);
595
596 /*
597 * set load & XFontStruct
598 */
599 fdata->flist[i].load = 0;
600
601 /*
602 * This appears to be a bogus check. The actual intent appears
603 * to be to find out whether this is the "base" font in a set,
604 * rather than iso8859_1 explicitly. Note that iso8859_15 will
605 * and must also pass this test.
606 */
607
608 if (fdata->xfont == NULL &&
609 strstr(fdata->flist[i].charset_name, "8859_1")) {
610 fdata->flist[i].xfont =
611 loadFont(awt_display, fdata->flist[i].xlfd, size * 10);
612 if (fdata->flist[i].xfont != NULL) {
613 fdata->flist[i].load = 1;
614 fdata->xfont = fdata->flist[i].xfont;
615 fdata->flist[i].index_length = 1;
616 } else {
617 if (errmsg != NULL) {
618 *errmsg = "java/lang" "NullPointerException";
619 }
620 (*env)->DeleteLocalRef(env, componentFonts);
621 return NULL;
622 }
623 }
624 }
625 (*env)->DeleteLocalRef(env, componentFonts);
626 /*
627 * XFontSet will create if the peer of TextField/TextArea
628 * are used.
629 */
630 fdata->xfs = NULL;
631
632 JNU_SetLongFieldFromPtr(env,font,fontIDs.pData,fdata);
633 Disposer_AddRecord(env, font, pDataDisposeMethod, ptr_to_jlong(fdata));
634 return fdata;
635 } else {
636 Display *display = NULL;
637 struct FontData *fdata = NULL;
638 char fontSpec[1024];
639 int32_t height;
640 int32_t oheight;
641 int32_t above = 0; /* tries above height */
642 int32_t below = 0; /* tries below height */
643 char *foundry = NULL;
644 char *name = NULL;
645 char *encoding = NULL;
646 char *style = NULL;
647 XFontStruct *xfont = NULL;
648 jstring family = NULL;
649
650 if (JNU_IsNull(env, font)) {
651 if (errmsg != NULL) {
652 *errmsg = "java/lang" "NullPointerException";
653 }
654 return (struct FontData *) NULL;
655 }
656 display = XDISPLAY;
657
658 fdata = (struct FontData *) JNU_GetLongFieldAsPtr(env,font,fontIDs.pData);
659 if (fdata != NULL && fdata->xfont != NULL) {
660 return fdata;
661 }
662
663 family = (*env)->CallObjectMethod(env, font, fontIDs.getFamily);
664
665 if (!awtJNI_FontName(env, family, &foundry, &name, &encoding)) {
666 if (errmsg != NULL) {
667 *errmsg = "java/lang" "NullPointerException";
668 }
669 (*env)->DeleteLocalRef(env, family);
670 return (struct FontData *) NULL;
671 }
672 style = Style((*env)->GetIntField(env, font, fontIDs.style));
673 oheight = height = (*env)->GetIntField(env, font, fontIDs.size);
674
675 while (1) {
676 jio_snprintf(fontSpec, sizeof(fontSpec), "-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
677 foundry,
678 name,
679 style,
680 height,
681 encoding);
682
683 /*fprintf(stderr,"LoadFont: %s\n", fontSpec); */
684 xfont = XLoadQueryFont(display, fontSpec);
685
686 /* XXX: sometimes XLoadQueryFont returns a bogus font structure */
687 /* with negative ascent. */
688 if (xfont == (Font) NULL || xfont->ascent < 0) {
689 if (xfont != NULL) {
690 XFreeFont(display, xfont);
691 }
692 if (foundry != anyfoundry) { /* Use ptr comparison here, not strcmp */
693 /* Try any other foundry before messing with the sizes */
694 foundry = anyfoundry;
695 continue;
696 }
697 /* We couldn't find the font. We'll try to find an */
698 /* alternate by searching for heights above and below our */
699 /* preferred height. We try for 4 heights above and below. */
700 /* If we still can't find a font we repeat the algorithm */
701 /* using misc-fixed as the font. If we then fail, then we */
702 /* give up and signal an error. */
703 if (above == below) {
704 above++;
705 height = oheight + above;
706 } else {
707 below++;
708 if (below > 4) {
709 if (name != defaultfontname || style != anystyle) {
710 name = defaultfontname;
711 foundry = defaultfoundry;
712 height = oheight;
713 style = anystyle;
714 encoding = isolatin1;
715 above = below = 0;
716 continue;
717 } else {
718 if (errmsg != NULL) {
719 *errmsg = "java/io/" "FileNotFoundException";
720 }
721 (*env)->DeleteLocalRef(env, family);
722 return (struct FontData *) NULL;
723 }
724 }
725 height = oheight - below;
726 }
727 continue;
728 } else {
729 fdata = ZALLOC(FontData);
730
731 if (fdata == NULL) {
732 if (errmsg != NULL) {
733 *errmsg = "java/lang" "OutOfMemoryError";
734 }
735 } else {
736 fdata->xfont = xfont;
737 JNU_SetLongFieldFromPtr(env,font,fontIDs.pData,fdata);
738 Disposer_AddRecord(env, font, pDataDisposeMethod,
739 ptr_to_jlong(fdata));
740 }
741 (*env)->DeleteLocalRef(env, family);
742 return fdata;
743 }
744 }
745 /* not reached */
746 }
747}
748
749/*
750 * Class: sun_awt_motif_X11FontMetrics
751 * Method: getMFCharsWidth
752 * Signature: ([CIILjava/awt/Font;)I
753 */
754JNIEXPORT jint JNICALL Java_sun_awt_motif_X11FontMetrics_getMFCharsWidth
755 (JNIEnv *env, jobject this, jcharArray data, jint offset, jint length, jobject font)
756{
757 jint retVal = 0;
758
759 AWT_LOCK();
760
761 retVal = awtJNI_GetMFStringWidth(env, data, offset, length, font);
762
763 AWT_UNLOCK();
764 return retVal;
765}
766
767/*
768 * Class: sun_awt_motif_X11FontMetrics
769 * Method: bytesWidth
770 * Signature: ([BII)I
771 */
772JNIEXPORT jint JNICALL Java_sun_awt_motif_X11FontMetrics_bytesWidth
773 (JNIEnv *env, jobject this, jbyteArray str, jint off, jint len)
774{
775 jint w = 0;
776 unsigned char *s = NULL, *tmpPointer = NULL;
777 int32_t ch = 0;
778 int32_t cnt = 0;
779 jobject widths = NULL;
780 jint tempWidths[256];
781 jint maxAdvance = 0;
782 int32_t widlen = 0;
783
784 if (JNU_IsNull(env, str)) {
785 JNU_ThrowNullPointerException(env, "NullPointerException");
786 return 0;
787 }
788
789 cnt = (*env)->GetArrayLength(env, str);
790 if (cnt == 0) {
791 return 0;
792 }
793
794 widths = (*env)->GetObjectField(env, this, x11FontMetricsIDs.widths);
795 maxAdvance = (*env)->GetIntField(env, this, x11FontMetricsIDs.maxAdvance);
796 if (!JNU_IsNull(env, widths)) {
797 w = 0;
798 widlen = (*env)->GetArrayLength(env, widths);
799 (*env)->GetIntArrayRegion(env, widths, 0, widlen, (jint *) tempWidths);
800
801 s = tmpPointer = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, str, NULL);
802 if (s == NULL) {
803 return 0;
804 }
805
806 while (--cnt >= 0) {
807 ch = *tmpPointer++;
808 if (ch < widlen) {
809 w += tempWidths[ch];
810 } else {
811 w += maxAdvance;
812 }
813 }
814
815 (*env)->ReleasePrimitiveArrayCritical(env, str, (jchar *) s, JNI_ABORT);
816 } else {
817 w = maxAdvance * cnt;
818 }
819 return w;
820}
821
822/*
823 * Class: sun_awt_motif_X11FontMetrics
824 * Method: init
825 * Signature: ()V
826 */
827JNIEXPORT void JNICALL Java_sun_awt_motif_X11FontMetrics_init
828 (JNIEnv *env, jobject this)
829{
830 jobject font = NULL;
831 struct FontData *fdata = NULL;
832 jint tempWidths[256];
833 jintArray widths = NULL;
834 int32_t ccount = 0;
835 int32_t i = 0;
836 int32_t tempWidthsIndex = 0;
837 char *err = NULL;
838
839 if (JNU_IsNull(env, this)) {
840 JNU_ThrowNullPointerException(env, "NullPointerException");
841 return;
842 }
843 AWT_LOCK();
844
845 font = (*env)->GetObjectField(env, this, x11FontMetricsIDs.font);
846 if (JNU_IsNull(env, this)) {
847 JNU_ThrowNullPointerException(env, "NullPointerException");
848 AWT_UNLOCK();
849 return;
850 }
851 fdata = awtJNI_GetFontData(env, font, &err);
852 if (fdata == NULL) {
853 JNU_ThrowInternalError(env, err);
854 AWT_UNLOCK();
855 return;
856 }
857
858 /*
859 * Bug 4103248, 4120310. We must take all of the fonts into
860 * consideration in providing the metrics, not just the 8859-1 font,
861 * because the underlying Motif widgets are.
862 */
863 if (awtJNI_IsMultiFont(env, font) && fdata->xfs == NULL) {
864 fdata->xfs = awtJNI_MakeFontSet(env, font);
865 }
866 if (fdata->xfs != NULL) {
867 XFontSetExtents *fs_extents = NULL;
868 fs_extents = XExtentsOfFontSet(fdata->xfs);
869
870 (*env)->SetIntField(env, this, x11FontMetricsIDs.maxAscent,
871 (jint)(-fs_extents->max_logical_extent.y));
872 (*env)->SetIntField(env, this, x11FontMetricsIDs.maxDescent,
873 (jint)(fs_extents->max_logical_extent.height +
874 fs_extents->max_logical_extent.y));
875 (*env)->SetIntField(env, this, x11FontMetricsIDs.maxAdvance,
876 (jint)(fs_extents->max_logical_extent.width));
877 (*env)->SetIntField(env, this, x11FontMetricsIDs.ascent,
878 (jint)(-fs_extents->max_ink_extent.y));
879 (*env)->SetIntField(env, this, x11FontMetricsIDs.descent,
880 (jint)(fs_extents->max_ink_extent.height +
881 fs_extents->max_ink_extent.y));
882 } else {
883 (*env)->SetIntField(env, this, x11FontMetricsIDs.maxAscent,
884 (jint) fdata->xfont->max_bounds.ascent);
885 (*env)->SetIntField(env, this, x11FontMetricsIDs.maxDescent,
886 (jint) fdata->xfont->max_bounds.descent);
887 (*env)->SetIntField(env, this, x11FontMetricsIDs.maxAdvance,
888 (jint) fdata->xfont->max_bounds.width);
889 (*env)->SetIntField(env, this, x11FontMetricsIDs.ascent,
890 (jint) fdata->xfont->ascent);
891 (*env)->SetIntField(env, this, x11FontMetricsIDs.descent,
892 (jint) fdata->xfont->descent);
893 }
894
895 (*env)->SetIntField(env, this, x11FontMetricsIDs.leading, (jint) 1);
896 (*env)->SetIntField(env, this, x11FontMetricsIDs.height,
897 (jint) fdata->xfont->ascent + fdata->xfont->descent + 1);
898 (*env)->SetIntField(env, this, x11FontMetricsIDs.maxHeight,
899 (jint) fdata->xfont->max_bounds.ascent
900 + fdata->xfont->max_bounds.descent + 1);
901
902
903 widths = (*env)->NewIntArray(env, 256);
904 (*env)->SetObjectField(env, this, x11FontMetricsIDs.widths, widths);
905 if (JNU_IsNull(env, widths)) {
906 JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
907 AWT_UNLOCK();
908 return;
909 }
910 /*
911 * We could pin the array and then release it, but I believe this method
912 * is faster and perturbs the VM less
913 *
914 */
915 memset(tempWidths, 0, 256 * sizeof(jint));
916
917 tempWidthsIndex = fdata->xfont->min_char_or_byte2;
918
919 ccount = fdata->xfont->max_char_or_byte2 - fdata->xfont->min_char_or_byte2;
920
921 if (fdata->xfont->per_char) {
922 for (i = 0; i <= ccount; i++) {
923 tempWidths[tempWidthsIndex++] = (jint) fdata->xfont->per_char[i].width;
924 }
925 } else {
926 for (i = 0; i <= ccount; i++) {
927 tempWidths[tempWidthsIndex++] = (jint) fdata->xfont->max_bounds.width;
928 }
929 }
930
931 (*env)->SetIntArrayRegion(env, widths, 0, 256, (jint *) tempWidths);
932
933 AWT_UNLOCK();
934}
935
936/*
937 * Registered with the 2D disposer to be called after the Font is GC'd.
938 */
939static void pDataDisposeMethod(JNIEnv *env, jlong pData)
940{
941 struct FontData *fdata = NULL;
942 int32_t i = 0;
943 Display *display = XDISPLAY;
944
945 AWT_LOCK();
946 fdata = (struct FontData *)pData;
947
948 if (fdata == NULL) {
949 AWT_UNLOCK();
950 return;
951 }
952
953 if (fdata->xfs != NULL) {
954 XFreeFontSet(display, fdata->xfs);
955 }
956
957 /* AWT fonts are always "multifonts" and probably have been in
958 * all post 1.0 releases, so this test test for multi fonts is
959 * probably not needed, and the singleton xfont is probably never used.
960 */
961 if (fdata->charset_num > 0) {
962 for (i = 0; i < fdata->charset_num; i++) {
963 free((void *)fdata->flist[i].xlfd);
964 JNU_ReleaseStringPlatformChars(env, NULL,
965 fdata->flist[i].charset_name);
966 if (fdata->flist[i].load) {
967 XFreeFont(display, fdata->flist[i].xfont);
968 }
969 }
970
971 free((void *)fdata->flist);
972
973 /* Don't free fdata->xfont because it is equal to fdata->flist[i].xfont
974 for some 'i' */
975 } else {
976 if (fdata->xfont != NULL) {
977 XFreeFont(display, fdata->xfont);
978 }
979 }
980
981 free((void *)fdata);
982
983 AWT_UNLOCK();
984}
985#endif /* !HEADLESS */