1/*
2 * Copyright (c) 1995, 2014, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * 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_X11GraphicsEnvironment.h"
34
35#include "awt_Font.h"
36
37#include "java_awt_Dimension.h"
38#include "multi_font.h"
39#include "Disposer.h"
40#endif /* !HEADLESS */
41#include <jni.h>
42#ifndef HEADLESS
43#include <jni_util.h>
44
45#define defaultXLFD "-*-helvetica-*-*-*-*-12-*-*-*-*-*-iso8859-1"
46
47struct FontIDs fontIDs;
48struct PlatformFontIDs platformFontIDs;
49
50static void pDataDisposeMethod(JNIEnv *env, jlong pData);
51
52/* #define FONT_DEBUG 2 */
53/* 1- print failures, 2- print all, 3- terminate on failure */
54#if FONT_DEBUG
55static XFontStruct *XLoadQueryFontX(Display *display, char *name)
56{
57 XFontStruct *result = NULL;
58 result = XLoadQueryFont(display, name);
59#if FONT_DEBUG < 2
60 if (result == NULL)
61#endif
62 fprintf(stderr, "XLoadQueryFont(\"%s\") -> 0x%x.\n", name, result);
63#if FONT_DEBUG >= 3
64 if (result == NULL)
65 exit(-1);
66#endif
67 return result;
68}
69#define XLoadQueryFont XLoadQueryFontX
70#endif
71#endif /* !HEADLESS */
72
73/*
74 * Class: java_awt_Font
75 * Method: initIDs
76 * Signature: ()V
77 */
78
79/* This function gets called from the static initializer for Font.java
80 to initialize the fieldIDs for fields that may be accessed from C */
81
82JNIEXPORT void JNICALL
83Java_java_awt_Font_initIDs
84 (JNIEnv *env, jclass cls)
85{
86#ifndef HEADLESS
87 CHECK_NULL(fontIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"));
88 CHECK_NULL(fontIDs.style = (*env)->GetFieldID(env, cls, "style", "I"));
89 CHECK_NULL(fontIDs.size = (*env)->GetFieldID(env, cls, "size", "I"));
90 CHECK_NULL(fontIDs.getPeer = (*env)->GetMethodID(env, cls, "getFontPeer",
91 "()Ljava/awt/peer/FontPeer;"));
92 CHECK_NULL(fontIDs.getFamily = (*env)->GetMethodID(env, cls, "getFamily_NoClientCode",
93 "()Ljava/lang/String;"));
94#endif /* !HEADLESS */
95}
96
97#ifndef HEADLESS
98/* fieldIDs for FontDescriptor fields that may be accessed from C */
99static struct FontDescriptorIDs {
100 jfieldID nativeName;
101 jfieldID charsetName;
102} fontDescriptorIDs;
103#endif /* !HEADLESS */
104
105/*
106 * Class: sun_awt_FontDescriptor
107 * Method: initIDs
108 * Signature: ()V
109 */
110
111/* This function gets called from the static initializer for
112 FontDescriptor.java to initialize the fieldIDs for fields
113 that may be accessed from C */
114
115JNIEXPORT void JNICALL
116Java_sun_awt_FontDescriptor_initIDs
117 (JNIEnv *env, jclass cls)
118{
119#ifndef HEADLESS
120 CHECK_NULL(fontDescriptorIDs.nativeName =
121 (*env)->GetFieldID(env, cls, "nativeName", "Ljava/lang/String;"));
122 CHECK_NULL(fontDescriptorIDs.charsetName =
123 (*env)->GetFieldID(env, cls, "charsetName", "Ljava/lang/String;"));
124#endif /* !HEADLESS */
125}
126
127/*
128 * Class: sun_awt_PlatformFont
129 * Method: initIDs
130 * Signature: ()V
131 */
132
133/* This function gets called from the static initializer for
134 PlatformFont.java to initialize the fieldIDs for fields
135 that may be accessed from C */
136
137JNIEXPORT void JNICALL
138Java_sun_awt_PlatformFont_initIDs
139 (JNIEnv *env, jclass cls)
140{
141#ifndef HEADLESS
142 CHECK_NULL(platformFontIDs.componentFonts =
143 (*env)->GetFieldID(env, cls, "componentFonts",
144 "[Lsun/awt/FontDescriptor;"));
145 CHECK_NULL(platformFontIDs.fontConfig =
146 (*env)->GetFieldID(env,cls, "fontConfig",
147 "Lsun/awt/FontConfiguration;"));
148 CHECK_NULL(platformFontIDs.makeConvertedMultiFontString =
149 (*env)->GetMethodID(env, cls, "makeConvertedMultiFontString",
150 "(Ljava/lang/String;)[Ljava/lang/Object;"));
151 CHECK_NULL(platformFontIDs.makeConvertedMultiFontChars =
152 (*env)->GetMethodID(env, cls, "makeConvertedMultiFontChars",
153 "([CII)[Ljava/lang/Object;"));
154#endif /* !HEADLESS */
155}
156
157#ifndef HEADLESS
158XFontStruct *
159loadFont(Display * display, char *name, int32_t pointSize)
160{
161 XFontStruct *f = NULL;
162
163 /* try the exact xlfd name in font configuration file */
164 f = XLoadQueryFont(display, name);
165 if (f != NULL) {
166 return f;
167 }
168
169 /*
170 * try nearly font
171 *
172 * 1. specify FAMILY_NAME, WEIGHT_NAME, SLANT, POINT_SIZE,
173 * CHARSET_REGISTRY and CHARSET_ENCODING.
174 * 2. change POINT_SIZE to PIXEL_SIZE
175 * 3. change FAMILY_NAME to *
176 * 4. specify only PIXEL_SIZE and CHARSET_REGISTRY/ENCODING
177 * 5. change PIXEL_SIZE +1/-1/+2/-2...+4/-4
178 * 6. default font pattern
179 */
180 {
181 /*
182 * This code assumes the name contains exactly 14 '-' delimiter.
183 * If not use default pattern.
184 */
185 int32_t i, length, pixelSize;
186 Boolean useDefault = FALSE;
187
188 char buffer[BUFSIZ], buffer2[BUFSIZ];
189 char *family = NULL, *style = NULL, *slant = NULL, *encoding = NULL;
190 char *start = NULL, *end = NULL;
191
192 if (strlen(name) > BUFSIZ - 1) {
193 useDefault = TRUE;
194 } else {
195 strcpy(buffer, name);
196 }
197
198#define NEXT_HYPHEN\
199 start = end + 1;\
200 end = strchr(start, '-');\
201 if (end == NULL) {\
202 useDefault = TRUE;\
203 break;\
204 }\
205 *end = '\0'
206
207 do {
208 end = buffer;
209
210 /* skip FOUNDRY */
211 NEXT_HYPHEN;
212
213 /* set FAMILY_NAME */
214 NEXT_HYPHEN;
215 family = start;
216
217 /* set STYLE_NAME */
218 NEXT_HYPHEN;
219 style = start;
220
221 /* set SLANT */
222 NEXT_HYPHEN;
223 slant = start;
224
225 /* skip SETWIDTH_NAME, ADD_STYLE_NAME, PIXEL_SIZE
226 POINT_SIZE, RESOLUTION_X, RESOLUTION_Y, SPACING
227 and AVERAGE_WIDTH */
228 NEXT_HYPHEN;
229 NEXT_HYPHEN;
230 NEXT_HYPHEN;
231 NEXT_HYPHEN;
232 NEXT_HYPHEN;
233 NEXT_HYPHEN;
234 NEXT_HYPHEN;
235 NEXT_HYPHEN;
236
237 /* set CHARSET_REGISTRY and CHARSET_ENCODING */
238 encoding = end + 1;
239 }
240 while (0);
241
242#define TRY_LOAD\
243 f = XLoadQueryFont(display, buffer2);\
244 if (f != NULL) {\
245 strcpy(name, buffer2);\
246 return f;\
247 }
248
249 if (!useDefault) {
250 char *altstyle = NULL;
251
252 /* Regular is the style for TrueType fonts -- Type1, F3 use roman */
253 if (strcmp(style, "regular") == 0) {
254 altstyle = "roman";
255 }
256#if defined(__linux__) || defined(MACOSX)
257 if (!strcmp(family, "lucidasans")) {
258 family = "lucida";
259 }
260#endif
261 /* try 1. */
262 jio_snprintf(buffer2, sizeof(buffer2),
263 "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",
264 family, style, slant, pointSize, encoding);
265 TRY_LOAD;
266
267 if (altstyle != NULL) {
268 jio_snprintf(buffer2, sizeof(buffer2),
269 "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-%s",
270 family, altstyle, slant, pointSize, encoding);
271 TRY_LOAD;
272 }
273
274 /* search bitmap font */
275 pixelSize = pointSize / 10;
276
277 /* try 2. */
278 jio_snprintf(buffer2, sizeof(buffer2),
279 "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
280 family, style, slant, pixelSize, encoding);
281 TRY_LOAD;
282
283 if (altstyle != NULL) {
284 jio_snprintf(buffer2, sizeof(buffer2),
285 "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
286 family, altstyle, slant, pixelSize, encoding);
287 TRY_LOAD;
288 }
289
290 /* try 3 */
291 jio_snprintf(buffer2, sizeof(buffer2),
292 "-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",
293 style, slant, pixelSize, encoding);
294 TRY_LOAD;
295 if (altstyle != NULL) {
296 jio_snprintf(buffer2, sizeof(buffer2),
297 "-*-*-%s-%s-*-*-%d-*-*-*-*-*-%s",
298 altstyle, slant, pixelSize, encoding);
299 TRY_LOAD;
300 }
301
302 /* try 4 */
303 jio_snprintf(buffer2, sizeof(buffer2),
304 "-*-*-*-%s-*-*-%d-*-*-*-*-*-%s",
305 slant, pixelSize, encoding);
306
307 TRY_LOAD;
308
309 /* try 5. */
310 jio_snprintf(buffer2, sizeof(buffer2),
311 "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
312 pixelSize, encoding);
313 TRY_LOAD;
314
315 /* try 6. */
316 for (i = 1; i < 4; i++) {
317 if (pixelSize < i)
318 break;
319 jio_snprintf(buffer2, sizeof(buffer2),
320 "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
321 family, style, slant, pixelSize + i, encoding);
322 TRY_LOAD;
323
324 jio_snprintf(buffer2, sizeof(buffer2),
325 "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
326 family, style, slant, pixelSize - i, encoding);
327 TRY_LOAD;
328
329 jio_snprintf(buffer2, sizeof(buffer2),
330 "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
331 pixelSize + i, encoding);
332 TRY_LOAD;
333
334 jio_snprintf(buffer2, sizeof(buffer2),
335 "-*-*-*-*-*-*-%d-*-*-*-*-*-%s",
336 pixelSize - i, encoding);
337 TRY_LOAD;
338 }
339 }
340 }
341
342 strcpy(name, defaultXLFD);
343 return XLoadQueryFont(display, defaultXLFD);
344}
345
346/*
347 * Hardwired list of mappings for generic font names "Helvetica",
348 * "TimesRoman", "Courier", "Dialog", and "DialogInput".
349 */
350static char *defaultfontname = "fixed";
351static char *defaultfoundry = "misc";
352static char *anyfoundry = "*";
353static char *anystyle = "*-*";
354static char *isolatin1 = "iso8859-1";
355
356static char *
357Style(int32_t s)
358{
359 switch (s) {
360 case java_awt_Font_ITALIC:
361 return "medium-i";
362 case java_awt_Font_BOLD:
363 return "bold-r";
364 case java_awt_Font_BOLD + java_awt_Font_ITALIC:
365 return "bold-i";
366 case java_awt_Font_PLAIN:
367 default:
368 return "medium-r";
369 }
370}
371
372static int32_t
373awtJNI_FontName(JNIEnv * env, jstring name, char **foundry, char **facename, char **encoding)
374{
375 char *cname = NULL;
376
377 if (JNU_IsNull(env, name)) {
378 return 0;
379 }
380 cname = (char *) JNU_GetStringPlatformChars(env, name, NULL);
381 if (cname == NULL) {
382 (*env)->ExceptionClear(env);
383 JNU_ThrowOutOfMemoryError(env, "Could not create font name");
384 return 0;
385 }
386
387 /* additional default font names */
388 if (strcmp(cname, "serif") == 0) {
389 *foundry = "adobe";
390 *facename = "times";
391 *encoding = isolatin1;
392 } else if (strcmp(cname, "sansserif") == 0) {
393 *foundry = "adobe";
394 *facename = "helvetica";
395 *encoding = isolatin1;
396 } else if (strcmp(cname, "monospaced") == 0) {
397 *foundry = "adobe";
398 *facename = "courier";
399 *encoding = isolatin1;
400 } else if (strcmp(cname, "helvetica") == 0) {
401 *foundry = "adobe";
402 *facename = "helvetica";
403 *encoding = isolatin1;
404 } else if (strcmp(cname, "timesroman") == 0) {
405 *foundry = "adobe";
406 *facename = "times";
407 *encoding = isolatin1;
408 } else if (strcmp(cname, "courier") == 0) {
409 *foundry = "adobe";
410 *facename = "courier";
411 *encoding = isolatin1;
412 } else if (strcmp(cname, "dialog") == 0) {
413 *foundry = "b&h";
414 *facename = "lucida";
415 *encoding = isolatin1;
416 } else if (strcmp(cname, "dialoginput") == 0) {
417 *foundry = "b&h";
418 *facename = "lucidatypewriter";
419 *encoding = isolatin1;
420 } else if (strcmp(cname, "zapfdingbats") == 0) {
421 *foundry = "itc";
422 *facename = "zapfdingbats";
423 *encoding = "*-*";
424 } else {
425#ifdef DEBUG
426 jio_fprintf(stderr, "Unknown font: %s\n", cname);
427#endif
428 *foundry = defaultfoundry;
429 *facename = defaultfontname;
430 *encoding = isolatin1;
431 }
432
433 if (cname != NULL)
434 JNU_ReleaseStringPlatformChars(env, name, (const char *) cname);
435
436 return 1;
437}
438
439struct FontData *
440awtJNI_GetFontData(JNIEnv * env, jobject font, char **errmsg)
441{
442 /* We are going to create at most 4 outstanding local refs in this
443 * function. */
444 if ((*env)->EnsureLocalCapacity(env, 4) < 0) {
445 return NULL;
446 }
447
448 if (!JNU_IsNull(env, font) && awtJNI_IsMultiFont(env, font)) {
449 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
450
451 struct FontData *fdata = NULL;
452 int32_t i, size;
453 char *fontsetname = NULL;
454 char *nativename = NULL;
455 Boolean doFree = FALSE;
456 jobjectArray componentFonts = NULL;
457 jobject peer = NULL;
458 jobject fontDescriptor = NULL;
459 jstring fontDescriptorName = NULL;
460 jstring charsetName = NULL;
461
462 fdata = (struct FontData *) JNU_GetLongFieldAsPtr(env,font,
463 fontIDs.pData);
464
465 if (fdata != NULL && fdata->flist != NULL) {
466 return fdata;
467 }
468 size = (*env)->GetIntField(env, font, fontIDs.size);
469 fdata = (struct FontData *) malloc(sizeof(struct FontData));
470
471 peer = (*env)->CallObjectMethod(env, font, fontIDs.getPeer);
472
473 componentFonts =
474 (*env)->GetObjectField(env, peer, platformFontIDs.componentFonts);
475 /* We no longer need peer */
476 (*env)->DeleteLocalRef(env, peer);
477
478 fdata->charset_num = (*env)->GetArrayLength(env, componentFonts);
479
480 fdata->flist = (awtFontList *) malloc(sizeof(awtFontList)
481 * fdata->charset_num);
482 fdata->xfont = NULL;
483 for (i = 0; i < fdata->charset_num; i++) {
484 /*
485 * set xlfd name
486 */
487
488 fontDescriptor = (*env)->GetObjectArrayElement(env, componentFonts, i);
489 fontDescriptorName =
490 (*env)->GetObjectField(env, fontDescriptor,
491 fontDescriptorIDs.nativeName);
492
493 if (!JNU_IsNull(env, fontDescriptorName)) {
494 nativename = (char *) JNU_GetStringPlatformChars(env, fontDescriptorName, NULL);
495 if (nativename == NULL) {
496 nativename = "";
497 doFree = FALSE;
498 } else {
499 doFree = TRUE;
500 }
501 } else {
502 nativename = "";
503 doFree = FALSE;
504 }
505
506 fdata->flist[i].xlfd = malloc(strlen(nativename)
507 + strlen(defaultXLFD));
508 jio_snprintf(fdata->flist[i].xlfd, strlen(nativename) + 10,
509 nativename, size * 10);
510
511 if (nativename != NULL && doFree)
512 JNU_ReleaseStringPlatformChars(env, fontDescriptorName, (const char *) nativename);
513
514 /*
515 * set charset_name
516 */
517
518 charsetName =
519 (*env)->GetObjectField(env, fontDescriptor,
520 fontDescriptorIDs.charsetName);
521
522 fdata->flist[i].charset_name = (char *)
523 JNU_GetStringPlatformChars(env, charsetName, NULL);
524 if (fdata->flist[i].charset_name == NULL) {
525 (*env)->ExceptionClear(env);
526 JNU_ThrowOutOfMemoryError(env, "Could not create charset name");
527 return NULL;
528 }
529
530 /* We are done with the objects. */
531 (*env)->DeleteLocalRef(env, fontDescriptor);
532 (*env)->DeleteLocalRef(env, fontDescriptorName);
533 (*env)->DeleteLocalRef(env, charsetName);
534
535 /*
536 * set load & XFontStruct
537 */
538 fdata->flist[i].load = 0;
539
540 /*
541 * This appears to be a bogus check. The actual intent appears
542 * to be to find out whether this is the "base" font in a set,
543 * rather than iso8859_1 explicitly. Note that iso8859_15 will
544 * and must also pass this test.
545 */
546
547 if (fdata->xfont == NULL &&
548 strstr(fdata->flist[i].charset_name, "8859_1")) {
549 fdata->flist[i].xfont =
550 loadFont(awt_display, fdata->flist[i].xlfd, size * 10);
551 if (fdata->flist[i].xfont != NULL) {
552 fdata->flist[i].load = 1;
553 fdata->xfont = fdata->flist[i].xfont;
554 fdata->flist[i].index_length = 1;
555 } else {
556 /* Free any already allocated storage and fonts */
557 int j = i;
558 for (j = 0; j <= i; j++) {
559 free((void *)fdata->flist[j].xlfd);
560 JNU_ReleaseStringPlatformChars(env, NULL,
561 fdata->flist[j].charset_name);
562 if (fdata->flist[j].load) {
563 XFreeFont(awt_display, fdata->flist[j].xfont);
564 }
565 }
566 free((void *)fdata->flist);
567 free((void *)fdata);
568
569 if (errmsg != NULL) {
570 *errmsg = "java/lang" "NullPointerException";
571 }
572 (*env)->DeleteLocalRef(env, componentFonts);
573 return NULL;
574 }
575 }
576 }
577 (*env)->DeleteLocalRef(env, componentFonts);
578 /*
579 * XFontSet will create if the peer of TextField/TextArea
580 * are used.
581 */
582 fdata->xfs = NULL;
583
584 JNU_SetLongFieldFromPtr(env,font,fontIDs.pData,fdata);
585 Disposer_AddRecord(env, font, pDataDisposeMethod, ptr_to_jlong(fdata));
586 return fdata;
587 } else {
588 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
589 Display *display = NULL;
590 struct FontData *fdata = NULL;
591 char fontSpec[1024];
592 int32_t height;
593 int32_t oheight;
594 int32_t above = 0; /* tries above height */
595 int32_t below = 0; /* tries below height */
596 char *foundry = NULL;
597 char *name = NULL;
598 char *encoding = NULL;
599 char *style = NULL;
600 XFontStruct *xfont = NULL;
601 jstring family = NULL;
602
603 if (JNU_IsNull(env, font)) {
604 if (errmsg != NULL) {
605 *errmsg = "java/lang" "NullPointerException";
606 }
607 return (struct FontData *) NULL;
608 }
609 display = XDISPLAY;
610
611 fdata = (struct FontData *) JNU_GetLongFieldAsPtr(env,font,fontIDs.pData);
612 if (fdata != NULL && fdata->xfont != NULL) {
613 return fdata;
614 }
615
616 family = (*env)->CallObjectMethod(env, font, fontIDs.getFamily);
617
618 if (!awtJNI_FontName(env, family, &foundry, &name, &encoding)) {
619 if (errmsg != NULL) {
620 *errmsg = "java/lang" "NullPointerException";
621 }
622 (*env)->DeleteLocalRef(env, family);
623 return (struct FontData *) NULL;
624 }
625 style = Style((*env)->GetIntField(env, font, fontIDs.style));
626 oheight = height = (*env)->GetIntField(env, font, fontIDs.size);
627
628 while (1) {
629 jio_snprintf(fontSpec, sizeof(fontSpec), "-%s-%s-%s-*-*-%d-*-*-*-*-*-%s",
630 foundry,
631 name,
632 style,
633 height,
634 encoding);
635
636 /*fprintf(stderr,"LoadFont: %s\n", fontSpec); */
637 xfont = XLoadQueryFont(display, fontSpec);
638
639 /* XXX: sometimes XLoadQueryFont returns a bogus font structure */
640 /* with negative ascent. */
641 if (xfont == NULL || xfont->ascent < 0) {
642 if (xfont != NULL) {
643 XFreeFont(display, xfont);
644 }
645 if (foundry != anyfoundry) { /* Use ptr comparison here, not strcmp */
646 /* Try any other foundry before messing with the sizes */
647 foundry = anyfoundry;
648 continue;
649 }
650 /* We couldn't find the font. We'll try to find an */
651 /* alternate by searching for heights above and below our */
652 /* preferred height. We try for 4 heights above and below. */
653 /* If we still can't find a font we repeat the algorithm */
654 /* using misc-fixed as the font. If we then fail, then we */
655 /* give up and signal an error. */
656 if (above == below) {
657 above++;
658 height = oheight + above;
659 } else {
660 below++;
661 if (below > 4) {
662 if (name != defaultfontname || style != anystyle) {
663 name = defaultfontname;
664 foundry = defaultfoundry;
665 height = oheight;
666 style = anystyle;
667 encoding = isolatin1;
668 above = below = 0;
669 continue;
670 } else {
671 if (errmsg != NULL) {
672 *errmsg = "java/io/" "FileNotFoundException";
673 }
674 (*env)->DeleteLocalRef(env, family);
675 return (struct FontData *) NULL;
676 }
677 }
678 height = oheight - below;
679 }
680 continue;
681 } else {
682 fdata = ZALLOC(FontData);
683
684 if (fdata == NULL) {
685 if (errmsg != NULL) {
686 *errmsg = "java/lang" "OutOfMemoryError";
687 }
688 } else {
689 fdata->xfont = xfont;
690 JNU_SetLongFieldFromPtr(env,font,fontIDs.pData,fdata);
691 Disposer_AddRecord(env, font, pDataDisposeMethod,
692 ptr_to_jlong(fdata));
693 }
694 (*env)->DeleteLocalRef(env, family);
695 return fdata;
696 }
697 }
698 /* not reached */
699 }
700}
701
702/*
703 * Registered with the 2D disposer to be called after the Font is GC'd.
704 */
705static void pDataDisposeMethod(JNIEnv *env, jlong pData)
706{
707 struct FontData *fdata = NULL;
708 int32_t i = 0;
709 Display *display = XDISPLAY;
710
711 AWT_LOCK();
712 fdata = (struct FontData *)pData;
713
714 if (fdata == NULL) {
715 AWT_UNLOCK();
716 return;
717 }
718
719 if (fdata->xfs != NULL) {
720 XFreeFontSet(display, fdata->xfs);
721 }
722
723 /* AWT fonts are always "multifonts" and probably have been in
724 * all post 1.0 releases, so this test for multi fonts is
725 * probably not needed, and the singleton xfont is probably never used.
726 */
727 if (fdata->charset_num > 0) {
728 for (i = 0; i < fdata->charset_num; i++) {
729 free((void *)fdata->flist[i].xlfd);
730 JNU_ReleaseStringPlatformChars(env, NULL,
731 fdata->flist[i].charset_name);
732 if (fdata->flist[i].load) {
733 XFreeFont(display, fdata->flist[i].xfont);
734 }
735 }
736
737 free((void *)fdata->flist);
738
739 /* Don't free fdata->xfont because it is equal to fdata->flist[i].xfont
740 for some 'i' */
741 } else {
742 if (fdata->xfont != NULL) {
743 XFreeFont(display, fdata->xfont);
744 }
745 }
746
747 free((void *)fdata);
748
749 AWT_UNLOCK();
750}
751#endif /* !HEADLESS */
752