blob: aad6bfec9925c61bac668f30b463e914db9fc46d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-2005 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/*
27 * These routines are used for display string with multi font.
28 */
29
30#ifdef HEADLESS
31 #error This file should not be included in headless library
32#endif
33
34#include <stdlib.h>
35#include <string.h>
36#include <math.h>
37#include <ctype.h>
38#include <jni.h>
39#include <jni_util.h>
40#include <jvm.h>
41#ifndef XAWT
42#include <Xm/Display.h>
43#endif
44#include "awt_Font.h"
45#ifndef XAWT
46#include "awt_Component.h"
47#endif
48#include "awt_MenuItem.h"
49#include "awt_p.h"
50#include "multi_font.h"
51
52extern XFontStruct *loadFont(Display *, char *, int32_t);
53
54extern struct FontIDs fontIDs;
55extern struct MComponentPeerIDs mComponentPeerIDs;
56extern struct MMenuItemPeerIDs mMenuItemPeerIDs;
57extern struct PlatformFontIDs platformFontIDs;
58extern struct MFontPeerIDs mFontPeerIDs;
59
60/*
61 * make string with str + string representation of num
62 * This string is used as tag string of Motif Compound String and FontList.
63 */
64static void
65makeTag(char *str, int32_t num, char *buf)
66{
67 int32_t len = strlen(str);
68
69 strcpy(buf, str);
70 buf[len] = '0' + num % 100;
71 buf[len + 1] = '\0';
72}
73#ifndef XAWT
74jobject
75awtJNI_CreateAndSetGlobalRef(JNIEnv * env, jobject this)
76{
77 jobject gRef;
78
79 gRef = (*env)->NewGlobalRef(env, this);
80
81 JNU_SetLongFieldFromPtr(env, this, mComponentPeerIDs.jniGlobalRef, gRef);
82
83 return gRef;
84}
85
86struct gRefStruct
87{
88 jobject gRef;
89 struct gRefStruct *next;
90};
91
92static struct gRefStruct *gRefHead = NULL;
93static struct gRefStruct *gRefTail = NULL;
94
95/*
96 * This function is called by components that
97 * are being disposed. It used to invalidate
98 * the global ref immediately, but the awt is
99 * rather full of thread race conditions involving
100 * component disposal and outstanding events.
101 * Now we queue up 'to be deleted' global refs
102 * as they come in, and don't invalidate them
103 * until the X event queue is empty. Callers of
104 * either of these functions _must_ have AWT_LOCK'd
105 * before using them!
106 */
107void
108awtJNI_DeleteGlobalRef(JNIEnv * env, jobject this)
109{
110 jobject gRef;
111 struct gRefStruct *newGRef;
112 struct gRefStruct *temp;
113
114 gRef = (jobject)
115 JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.jniGlobalRef);
116 JNU_SetLongFieldFromPtr(env, this, mComponentPeerIDs.jniGlobalRef, NULL);
117
118 /*
119 * Verra handy for tracking down race conditions. If you
120 * have a peer getting called after its been disposed...
121 */
122 /* jio_fprintf(stderr,"%p\n",(void *)gRef); */
123
124 newGRef = (struct gRefStruct *)malloc((size_t)sizeof(struct gRefStruct));
125
126 if(newGRef == NULL)
127 (*env)->DeleteGlobalRef(env, gRef);
128 else
129 {
130 newGRef->gRef = gRef;
131 newGRef->next = NULL;
132
133 if(gRefHead == NULL)
134 {
135 gRefTail = newGRef;
136 gRefHead = newGRef;
137 }
138 else
139 {
140 gRefTail->next = newGRef;
141 gRefTail = newGRef;
142 }
143 }
144}
145
146void
147awtJNI_DeleteGlobalMenuRef(JNIEnv * env, jobject this)
148{
149 jobject gRef;
150 struct gRefStruct *newGRef;
151 struct gRefStruct *temp;
152
153 gRef = (jobject)
154 JNU_GetLongFieldAsPtr(env, this, mMenuItemPeerIDs.jniGlobalRef);
155 JNU_SetLongFieldFromPtr(env, this, mMenuItemPeerIDs.jniGlobalRef, NULL);
156
157 /*
158 * Verra handy for tracking down race conditions. If you
159 * have a peer getting called after its been disposed...
160 */
161 /* jio_fprintf(stderr,"%p\n",(void *)gRef); */
162
163 newGRef = (struct gRefStruct *)malloc((size_t)sizeof(struct gRefStruct));
164
165 if(newGRef == NULL)
166 (*env)->DeleteGlobalRef(env, gRef);
167 else
168 {
169 newGRef->gRef = gRef;
170 newGRef->next = NULL;
171
172 if(gRefHead == NULL)
173 {
174 gRefTail = newGRef;
175 gRefHead = newGRef;
176 }
177 else
178 {
179 gRefTail->next = newGRef;
180 gRefTail = newGRef;
181 }
182 }
183}
184
185void awtJNI_CleanupGlobalRefs()
186{
187 struct gRefStruct *working,*next;
188 JNIEnv *env;
189 int32_t count = 0;
190
191 if(gRefHead == NULL) {
192 return;
193 }
194
195 env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
196
197 working = gRefHead;
198 gRefHead = gRefTail = NULL;
199
200 while(working != NULL)
201 {
202 count++;
203 next = working->next;
204 (*env)->DeleteGlobalRef(env, working->gRef);
205
206 free((void *)working);
207
208 working = next;
209 }
210}
211#endif
212static int32_t
213awtJNI_GetFontDescriptorNumber(JNIEnv * env
214 ,jobject font
215 ,jobject fd)
216{
217 int32_t i = 0, num;
218 /* initialize to NULL so that DeleteLocalRef will work. */
219 jobjectArray componentFonts = NULL;
220 jobject peer = NULL;
221 jobject temp = NULL;
222 jboolean validRet = JNI_FALSE;
223
224 if ((*env)->EnsureLocalCapacity(env, 2) < 0)
225 goto done;
226
227 peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
228 if (peer == NULL)
229 goto done;
230
231 componentFonts = (jobjectArray)
232 (*env)->GetObjectField(env,peer,platformFontIDs.componentFonts);
233
234 if (componentFonts == NULL)
235 goto done;
236
237 num = (*env)->GetArrayLength(env, componentFonts);
238
239 for (i = 0; i < num; i++) {
240 temp = (*env)->GetObjectArrayElement(env, componentFonts, i);
241
242 if ((*env)->IsSameObject(env, fd, temp)) {
243 validRet = JNI_TRUE;
244 break;
245 }
246 (*env)->DeleteLocalRef(env, temp);
247 }
248
249 done:
250 (*env)->DeleteLocalRef(env, peer);
251 (*env)->DeleteLocalRef(env, componentFonts);
252
253 if (validRet)
254 return i;
255
256 return 0;
257}
258#ifndef XAWT
259jobject
260awtJNI_GetFont(JNIEnv * env, jobject this)
261{
262 jobject target = NULL;
263 jobject font = NULL;
264
265 target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target);
266 // SECURITY: Must call _NoClientCode() methods to ensure that we
267 // are not invoking client code on the privileged thread
268 font = JNU_CallMethodByName(env,
269 NULL,
270 target,
271 "getFont_NoClientCode",
272 "()Ljava/awt/Font;").l;
273 (*env)->DeleteLocalRef(env, target);
274 return font;
275}
276#endif
277jobject
278awtJNI_GetFMFont(JNIEnv * env, jobject this)
279{
280 return JNU_CallMethodByName(env, NULL, this, "getFont_NoClientCode",
281 "()Ljava/awt/Font;").l;
282}
283
284jboolean
285awtJNI_IsMultiFont(JNIEnv * env, jobject this)
286{
287 jobject peer = NULL;
288 jobject fontConfig = NULL;
289
290 if (this == NULL) {
291 return JNI_FALSE;
292 }
293
294 if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
295 return JNI_FALSE;
296 }
297
298 peer = (*env)->CallObjectMethod(env,this,fontIDs.getPeer);
299 if (peer == NULL) {
300 return JNI_FALSE;
301 }
302
303 fontConfig = (*env)->GetObjectField(env,peer,platformFontIDs.fontConfig);
304 (*env)->DeleteLocalRef(env, peer);
305
306 if (fontConfig == NULL) {
307 return JNI_FALSE;
308 }
309 (*env)->DeleteLocalRef(env, fontConfig);
310
311 return JNI_TRUE;
312}
313
314jboolean
315awtJNI_IsMultiFontMetrics(JNIEnv * env, jobject this)
316{
317 jobject peer = NULL;
318 jobject fontConfig = NULL;
319 jobject font = NULL;
320
321 if (JNU_IsNull(env, this)) {
322 return JNI_FALSE;
323 }
324 if ((*env)->EnsureLocalCapacity(env, 3) < 0) {
325 return JNI_FALSE;
326 }
327
328 font = JNU_CallMethodByName(env, NULL, this, "getFont_NoClientCode",
329 "()Ljava/awt/Font;").l;
330 if (JNU_IsNull(env, font)) {
331 return JNI_FALSE;
332 }
333
334 peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
335 (*env)->DeleteLocalRef(env, font);
336
337 if (peer == NULL) {
338 return JNI_FALSE;
339 }
340
341 fontConfig = (*env)->GetObjectField(env,peer,platformFontIDs.fontConfig);
342 (*env)->DeleteLocalRef(env, peer);
343 if (fontConfig == NULL) {
344 return JNI_FALSE;
345 }
346 (*env)->DeleteLocalRef(env, fontConfig);
347
348 return JNI_TRUE;
349}
350#ifndef XAWT
351#ifdef __linux__
352XmString
353unicodeXmStringCreate(char* text, char* tag, int len) {
354 XmString ret_val;
355 XtProcessLock();
356 ret_val = _XmStringNCreate (text, tag, len);
357 XtProcessUnlock();
358 return ret_val;
359}
360#endif
361
362/*
363 * Unicode to Motif Multi Font Compound String converter
364 *
365 * ASSUMES: We are not running on a privileged thread
366 */
367XmString
368awtJNI_MakeMultiFontString(JNIEnv * env, jstring s, jobject font)
369{
370 XmString xmstr = NULL, xmtmp1, xmtmp2;
371 jobjectArray dataArray = NULL;
372 char *err = NULL;
373 int32_t stringCount,i;
374 int32_t fdnumber;
375 struct FontData *fdata = awtJNI_GetFontData(env, font, &err);
376 jobject fontDescriptor = NULL;
377 jbyteArray data = NULL;
378 char *stringData = NULL;
379 char tag[BUFSIZ];
380
381 if ((*env)->PushLocalFrame(env, 16) < 0)
382 return NULL;
383
384 if (!JNU_IsNull(env, s) && !JNU_IsNull(env, font)) {
385 jobject peer;
386
387 peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
388
389 DASSERT(!awt_currentThreadIsPrivileged(env));
390 dataArray =
391 (*env)->CallObjectMethod(
392 env,
393 peer,
394 platformFontIDs.makeConvertedMultiFontString,
395 s);
396
397 if ((*env)->ExceptionOccurred(env)) {
398 (*env)->ExceptionDescribe(env);
399 (*env)->ExceptionClear(env);
400
401 (*env)->PopLocalFrame(env, NULL);
402 return (XmString) NULL;
403 }
404
405 if(dataArray == NULL) {
406 (*env)->PopLocalFrame(env, NULL);
407 return (XmString) NULL;
408 }
409 } else {
410 (*env)->PopLocalFrame(env, NULL);
411 return (XmString) NULL;
412 }
413
414 stringCount = (*env)->GetArrayLength(env, dataArray);
415
416 for (i = 0; i < stringCount; i+=2) {
417 fontDescriptor = (*env)->GetObjectArrayElement(env, dataArray, i);
418 data = (*env)->GetObjectArrayElement(env, dataArray, i + 1);
419
420 /* Bail if we've finished */
421 if(fontDescriptor == NULL || data == NULL)
422 break;
423
424 fdnumber = awtJNI_GetFontDescriptorNumber(env, font, fontDescriptor);
425 fdata = awtJNI_GetFontData(env, font, &err);
426
427 makeTag(fdata->flist[fdnumber].charset_name, fdnumber, tag);
428
429 stringData = (char *)(*env)->GetPrimitiveArrayCritical(env, data, NULL);
430 if(stringData != NULL) {
431 unsigned char* buf = stringData;
432 int len;
433 char *offsetStringData;
434
435 offsetStringData = stringData + (4 * sizeof(char));
436#ifdef __linux__
437 len = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
438 /* Motif XmStringCreate() API requests "text must be a NULL-terminated
439 string" and its implementation uses "strlen()" to calculate the length
440 of the text string. Unfortunately when we deal with iso10646 font
441 on linux, the "text" is requested to be encoded in UTF16, which has the
442 posibility of including code points like "0xYY00" ("0xYY" + "0x00") that
443 causes problem when XmStringCreate() calls _XmStringNCreate() without
444 specifying a specific text lenth (see Motif XmString.c). The workaround is
445 to call _XmStringNCreate() directly with specific text length at this
446 cirsumstance.
447 */
448 if (strstr(fdata->flist[fdnumber].charset_name, "UnicodeBigUnmarked"))
449 xmtmp1 = unicodeXmStringCreate(offsetStringData, tag, len);
450 else
451 xmtmp1 = XmStringCreate(offsetStringData, tag);
452 if (xmstr == NULL)
453 xmstr = xmtmp1;
454 else {
455 xmtmp2 = XmStringConcat(xmstr, xmtmp1);
456 XmStringFree(xmtmp1);
457 XmStringFree(xmstr);
458 xmstr = xmtmp2;
459 }
460#else
461 if(xmstr == NULL) {
462 xmstr = XmStringCreate(offsetStringData, tag);
463 }
464 else {
465 xmtmp1 = XmStringCreate(offsetStringData, tag);
466 xmtmp2 = XmStringConcat(xmstr, xmtmp1);
467 XmStringFree(xmtmp1);
468 XmStringFree(xmstr);
469 xmstr = xmtmp2;
470 }
471#endif
472 }
473
474 (*env)->ReleasePrimitiveArrayCritical(env, data, stringData, JNI_ABORT);
475 (*env)->DeleteLocalRef(env, fontDescriptor);
476 (*env)->DeleteLocalRef(env, data);
477 }
478 (*env)->PopLocalFrame(env, NULL);
479 return xmstr;
480}
481
482/*
483 * Find the character encoding for a given font and register that encoding
484 * with the given tag. The encoding is the last two fields of the XLFD of
485 * the font (converted to uppercase).
486 */
487static void registerEncoding(char *xlfd, char *tag)
488{
489 char *e = xlfd + strlen(xlfd);
490 char *ret = NULL;
491
492 do { --e; } while (e != xlfd && *e != '-');
493 do { --e; } while (e != xlfd && *e != '-');
494 if (e != xlfd) {
495 char *encoding = strdup(++e);
496 char *u = NULL;
497
498 for (u = encoding; *u != '\0'; ++u) {
499 if (islower(*u)) {
500 *u = toupper(*u);
501 }
502 }
503
504 /*
505 * Motif will core dump on or otherwise mishandle unknown (or
506 * non-standard) character encodings (in conversion to compound
507 * text, bug 4122785). Register Sun private encodings for
508 * Symbol or dingbat fonts as ISO8859-1, which is a lie,
509 * but produces predictable results.
510 */
511 if (strncmp(encoding, "SUN-", 4) == 0) {
512 free(encoding);
513 encoding = strdup("ISO8859-1");
514 }
515 ret = XmRegisterSegmentEncoding(tag, encoding);
516 if (ret != NULL)
517 XtFree(ret);
518 free(encoding);
519 }
520}
521
522
523XmFontList
524awtJNI_GetFontList(JNIEnv * env, jobject font)
525{
526 int32_t i;
527 XmFontListEntry fle;
528 XmFontList fontlist;
529 XFontStruct *xf = NULL;
530 int32_t size;
531 struct FontData *fdata = NULL;
532 char *err = NULL, tag[BUFSIZ];
533
534 fdata = awtJNI_GetFontData(env, font, &err);
535
536 makeTag(fdata->flist[0].charset_name, 0, tag);
537
538 size = (int32_t) (*env)->GetIntField(env, font, fontIDs.size);
539
540 if (fdata->flist[0].load == 0) {
541 xf = loadFont(awt_display, fdata->flist[0].xlfd, size * 10);
542
543 if (xf == NULL) {
544 /* printf("Cannot load font: %s\n", fdata->list[0].xlfd); */
545 } else {
546 fdata->flist[0].xfont = xf;
547 fdata->flist[0].load = 1;
548
549 if (xf->min_byte1 == 0 && xf->max_byte1 == 0)
550 fdata->flist[0].index_length = 1;
551 else
552 fdata->flist[0].index_length = 2;
553 }
554 }
555 registerEncoding(fdata->flist[0].xlfd, tag);
556 fle = XmFontListEntryCreate(tag, XmFONT_IS_FONT,
557 (XtPointer) fdata->flist[0].xfont);
558
559 fontlist = XmFontListAppendEntry(NULL, fle);
560 /*
561 * Some versions of motif have a bug in
562 * XmFontListEntryFree() which causes it to free more than it
563 * should. Use XtFree() is used instead. See O'Reilly's
564 * Motif Reference Manual for more information.
565 */
566 XmFontListEntryFree(&fle);
567
568 for (i = 1; i < fdata->charset_num; i++) {
569 makeTag(fdata->flist[i].charset_name, i, tag);
570
571 if (fdata->flist[i].load == 0) {
572 xf = loadFont(awt_display, fdata->flist[i].xlfd, size * 10);
573
574 if (xf == NULL) {
575 /* printf("Cannot load font: %s\n", fdata->flist[0].xlfd); */
576 continue;
577 }
578 fdata->flist[i].xfont = xf;
579 fdata->flist[i].load = 1;
580 if (xf->min_byte1 == 0 && xf->max_byte1 == 0) {
581 fdata->flist[i].index_length = 1;
582 } else {
583 fdata->flist[i].index_length = 2;
584 }
585 }
586 registerEncoding(fdata->flist[i].xlfd, tag);
587 fle = XmFontListEntryCreate(tag, XmFONT_IS_FONT,
588 (XtPointer) fdata->flist[i].xfont);
589 fontlist = XmFontListAppendEntry(fontlist, fle);
590 /*
591 * Some versions of motif have a bug in
592 * XmFontListEntryFree() which causes it to free more than it
593 * should. Use XtFree() instead. See O'Reilly's
594 * Motif Reference Manual for more information.
595 */
596 XmFontListEntryFree(&fle);
597 }
598
599 return fontlist;
600}
601#endif
602/* #define FONT_DEBUG 2 */
603
604XFontSet
605awtJNI_MakeFontSet(JNIEnv * env, jobject font)
606{
607 jstring xlfd = NULL;
608 char *xfontset = NULL;
609 int32_t size;
610 int32_t length = 0;
611 char *realxlfd = NULL, *ptr = NULL, *prev = NULL;
612 char **missing_list = NULL;
613 int32_t missing_count;
614 char *def_string = NULL;
615 XFontSet xfs;
616 jobject peer = NULL;
617 jstring xfsname = NULL;
618#ifdef FONT_DEBUG
619 char xx[1024];
620#endif
621
622 if ((*env)->EnsureLocalCapacity(env, 2) < 0)
623 return 0;
624
625 size = (*env)->GetIntField(env, font, fontIDs.size) * 10;
626
627 peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
628 xfsname = (*env)->GetObjectField(env, peer, mFontPeerIDs.xfsname);
629
630 if (JNU_IsNull(env, xfsname))
631 xfontset = "";
632 else
633 xfontset = (char *)JNU_GetStringPlatformChars(env, xfsname, NULL);
634
635 realxlfd = malloc(strlen(xfontset) + 50);
636
637 prev = ptr = xfontset;
638 while ((ptr = strstr(ptr, "%d"))) {
639 char save = *(ptr + 2);
640
641 *(ptr + 2) = '\0';
642 jio_snprintf(realxlfd + length, strlen(xfontset) + 50 - length,
643 prev, size);
644 length = strlen(realxlfd);
645 *(ptr + 2) = save;
646
647 prev = ptr + 2;
648 ptr += 2;
649 }
650 strcpy(realxlfd + length, prev);
651
652#ifdef FONT_DEBUG
653 strcpy(xx, realxlfd);
654#endif
655 xfs = XCreateFontSet(awt_display, realxlfd, &missing_list,
656 &missing_count, &def_string);
657#if FONT_DEBUG >= 2
658 fprintf(stderr, "XCreateFontSet(%s)->0x%x\n", xx, xfs);
659#endif
660
661#if FONT_DEBUG
662 if (missing_count != 0) {
663 int32_t i;
664 fprintf(stderr, "XCreateFontSet missing %d fonts:\n", missing_count);
665 for (i = 0; i < missing_count; ++i) {
666 fprintf(stderr, "\t\"%s\"\n", missing_list[i]);
667 }
668 fprintf(stderr, " requested \"%s\"\n", xx);
669#if FONT_DEBUG >= 3
670 exit(-1);
671#endif
672 }
673#endif
674
675 free((void *)realxlfd);
676
677 if (xfontset && !JNU_IsNull(env, xfsname))
678 JNU_ReleaseStringPlatformChars(env, xfsname, (const char *) xfontset);
679
680 (*env)->DeleteLocalRef(env, peer);
681 (*env)->DeleteLocalRef(env, xfsname);
682 return xfs;
683}
684
685/*
686 * get multi font string width with multiple X11 font
687 *
688 * ASSUMES: We are not running on a privileged thread
689 */
690int32_t
691awtJNI_GetMFStringWidth(JNIEnv * env, jcharArray s, int offset, int sLength, jobject font)
692{
693 char *err = NULL;
694 unsigned char *stringData = NULL;
695 char *offsetStringData = NULL;
696 int32_t stringCount, i;
697 int32_t size;
698 struct FontData *fdata = NULL;
699 jobject fontDescriptor = NULL;
700 jbyteArray data = NULL;
701 int32_t j;
702 int32_t width = 0;
703 int32_t length;
704 XFontStruct *xf = NULL;
705 jobjectArray dataArray = NULL;
706#ifndef XAWT
707 DASSERT(!awt_currentThreadIsPrivileged(env));
708#endif
709 if ((*env)->EnsureLocalCapacity(env, 3) < 0)
710 return 0;
711
712 if (!JNU_IsNull(env, s) && !JNU_IsNull(env, font))
713 {
714 jobject peer;
715 peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
716
717 dataArray = (*env)->CallObjectMethod(
718 env,
719 peer,
720 platformFontIDs.makeConvertedMultiFontChars,
721 s, offset, sLength);
722
723 if ((*env)->ExceptionOccurred(env))
724 {
725 (*env)->ExceptionDescribe(env);
726 (*env)->ExceptionClear(env);
727 }
728
729 (*env)->DeleteLocalRef(env, peer);
730
731 if(dataArray == NULL)
732 {
733 return 0;
734 }
735 } else {
736 return 0;
737 }
738
739 fdata = awtJNI_GetFontData(env, font, &err);
740
741 stringCount = (*env)->GetArrayLength(env, dataArray);
742
743 size = (*env)->GetIntField(env, font, fontIDs.size);
744
745 for (i = 0; i < stringCount; i+=2)
746 {
747 fontDescriptor = (*env)->GetObjectArrayElement(env, dataArray, i);
748 data = (*env)->GetObjectArrayElement(env, dataArray, i + 1);
749
750 /* Bail if we've finished */
751 if (fontDescriptor == NULL || data == NULL) {
752 (*env)->DeleteLocalRef(env, fontDescriptor);
753 (*env)->DeleteLocalRef(env, data);
754 break;
755 }
756
757 j = awtJNI_GetFontDescriptorNumber(env, font, fontDescriptor);
758
759 if (fdata->flist[j].load == 0) {
760 xf = loadFont(awt_display,
761 fdata->flist[j].xlfd, size * 10);
762 if (xf == NULL) {
763 (*env)->DeleteLocalRef(env, fontDescriptor);
764 (*env)->DeleteLocalRef(env, data);
765 continue;
766 }
767 fdata->flist[j].load = 1;
768 fdata->flist[j].xfont = xf;
769 if (xf->min_byte1 == 0 && xf->max_byte1 == 0)
770 fdata->flist[j].index_length = 1;
771 else
772 fdata->flist[j].index_length = 2;
773 }
774 xf = fdata->flist[j].xfont;
775
776 stringData =
777 (unsigned char *)(*env)->GetPrimitiveArrayCritical(env, data,NULL);
778 length = (stringData[0] << 24) | (stringData[1] << 16) |
779 (stringData[2] << 8) | stringData[3];
780 offsetStringData = (char *)(stringData + (4 * sizeof(char)));
781
782 if (fdata->flist[j].index_length == 2) {
783 width += XTextWidth16(xf, (XChar2b *)offsetStringData, length/2);
784 } else {
785 width += XTextWidth(xf, offsetStringData, length);
786 }
787
788 (*env)->ReleasePrimitiveArrayCritical(env, data, stringData, JNI_ABORT);
789 (*env)->DeleteLocalRef(env, fontDescriptor);
790 (*env)->DeleteLocalRef(env, data);
791 }
792 (*env)->DeleteLocalRef(env, dataArray);
793
794 return width;
795}