1/*
2 * Copyright (c) 1996, 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/*
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#include "awt_Font.h"
42#include "awt_p.h"
43#include "multi_font.h"
44
45extern XFontStruct *loadFont(Display *, char *, int32_t);
46
47extern struct FontIDs fontIDs;
48extern struct PlatformFontIDs platformFontIDs;
49extern struct XFontPeerIDs xFontPeerIDs;
50
51/*
52 * make string with str + string representation of num
53 * This string is used as tag string of Motif Compound String and FontList.
54 */
55static void
56makeTag(char *str, int32_t num, char *buf)
57{
58 int32_t len = strlen(str);
59
60 strcpy(buf, str);
61 buf[len] = '0' + num % 100;
62 buf[len + 1] = '\0';
63}
64
65static int32_t
66awtJNI_GetFontDescriptorNumber(JNIEnv * env
67 ,jobject font
68 ,jobject fd)
69{
70 int32_t i = 0, num;
71 /* initialize to NULL so that DeleteLocalRef will work. */
72 jobjectArray componentFonts = NULL;
73 jobject peer = NULL;
74 jobject temp = NULL;
75 jboolean validRet = JNI_FALSE;
76
77 if ((*env)->EnsureLocalCapacity(env, 2) < 0 || (*env)->ExceptionCheck(env))
78 goto done;
79
80 peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
81 if (peer == NULL)
82 goto done;
83
84 componentFonts = (jobjectArray)
85 (*env)->GetObjectField(env,peer,platformFontIDs.componentFonts);
86
87 if (componentFonts == NULL)
88 goto done;
89
90 num = (*env)->GetArrayLength(env, componentFonts);
91
92 for (i = 0; i < num; i++) {
93 temp = (*env)->GetObjectArrayElement(env, componentFonts, i);
94
95 if ((*env)->IsSameObject(env, fd, temp)) {
96 validRet = JNI_TRUE;
97 break;
98 }
99 (*env)->DeleteLocalRef(env, temp);
100 }
101
102 done:
103 (*env)->DeleteLocalRef(env, peer);
104 (*env)->DeleteLocalRef(env, componentFonts);
105
106 if (validRet)
107 return i;
108
109 return 0;
110}
111
112jobject
113awtJNI_GetFMFont(JNIEnv * env, jobject this)
114{
115 return JNU_CallMethodByName(env, NULL, this, "getFont_NoClientCode",
116 "()Ljava/awt/Font;").l;
117}
118
119jboolean
120awtJNI_IsMultiFont(JNIEnv * env, jobject this)
121{
122 jobject peer = NULL;
123 jobject fontConfig = NULL;
124
125 if (this == NULL) {
126 return JNI_FALSE;
127 }
128
129 if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
130 return JNI_FALSE;
131 }
132
133 peer = (*env)->CallObjectMethod(env,this,fontIDs.getPeer);
134 if (peer == NULL) {
135 return JNI_FALSE;
136 }
137
138 fontConfig = (*env)->GetObjectField(env,peer,platformFontIDs.fontConfig);
139 (*env)->DeleteLocalRef(env, peer);
140
141 if (fontConfig == NULL) {
142 return JNI_FALSE;
143 }
144 (*env)->DeleteLocalRef(env, fontConfig);
145
146 return JNI_TRUE;
147}
148
149jboolean
150awtJNI_IsMultiFontMetrics(JNIEnv * env, jobject this)
151{
152 jobject peer = NULL;
153 jobject fontConfig = NULL;
154 jobject font = NULL;
155
156 if (JNU_IsNull(env, this)) {
157 return JNI_FALSE;
158 }
159 if ((*env)->EnsureLocalCapacity(env, 3) < 0) {
160 return JNI_FALSE;
161 }
162
163 font = JNU_CallMethodByName(env, NULL, this, "getFont_NoClientCode",
164 "()Ljava/awt/Font;").l;
165 if (JNU_IsNull(env, font) || (*env)->ExceptionCheck(env)) {
166 return JNI_FALSE;
167 }
168
169 peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
170 (*env)->DeleteLocalRef(env, font);
171
172 if (peer == NULL) {
173 return JNI_FALSE;
174 }
175
176 fontConfig = (*env)->GetObjectField(env,peer,platformFontIDs.fontConfig);
177 (*env)->DeleteLocalRef(env, peer);
178 if (fontConfig == NULL) {
179 return JNI_FALSE;
180 }
181 (*env)->DeleteLocalRef(env, fontConfig);
182
183 return JNI_TRUE;
184}
185
186/* #define FONT_DEBUG 2 */
187
188XFontSet
189awtJNI_MakeFontSet(JNIEnv * env, jobject font)
190{
191 jstring xlfd = NULL;
192 char *xfontset = NULL;
193 int32_t size;
194 int32_t length = 0;
195 char *realxlfd = NULL, *ptr = NULL, *prev = NULL;
196 char **missing_list = NULL;
197 int32_t missing_count;
198 char *def_string = NULL;
199 XFontSet xfs;
200 jobject peer = NULL;
201 jstring xfsname = NULL;
202#ifdef FONT_DEBUG
203 char xx[1024];
204#endif
205
206 if ((*env)->EnsureLocalCapacity(env, 2) < 0)
207 return 0;
208
209 size = (*env)->GetIntField(env, font, fontIDs.size) * 10;
210
211 peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
212 xfsname = (*env)->GetObjectField(env, peer, xFontPeerIDs.xfsname);
213
214 if (JNU_IsNull(env, xfsname))
215 xfontset = "";
216 else
217 xfontset = (char *)JNU_GetStringPlatformChars(env, xfsname, NULL);
218
219 realxlfd = malloc(strlen(xfontset) + 50);
220
221 prev = ptr = xfontset;
222 while ((ptr = strstr(ptr, "%d"))) {
223 char save = *(ptr + 2);
224
225 *(ptr + 2) = '\0';
226 jio_snprintf(realxlfd + length, strlen(xfontset) + 50 - length,
227 prev, size);
228 length = strlen(realxlfd);
229 *(ptr + 2) = save;
230
231 prev = ptr + 2;
232 ptr += 2;
233 }
234 strcpy(realxlfd + length, prev);
235
236#ifdef FONT_DEBUG
237 strcpy(xx, realxlfd);
238#endif
239 xfs = XCreateFontSet(awt_display, realxlfd, &missing_list,
240 &missing_count, &def_string);
241#if FONT_DEBUG >= 2
242 fprintf(stderr, "XCreateFontSet(%s)->0x%x\n", xx, xfs);
243#endif
244
245#if FONT_DEBUG
246 if (missing_count != 0) {
247 int32_t i;
248 fprintf(stderr, "XCreateFontSet missing %d fonts:\n", missing_count);
249 for (i = 0; i < missing_count; ++i) {
250 fprintf(stderr, "\t\"%s\"\n", missing_list[i]);
251 }
252 fprintf(stderr, " requested \"%s\"\n", xx);
253#if FONT_DEBUG >= 3
254 exit(-1);
255#endif
256 }
257#endif
258
259 free((void *)realxlfd);
260
261 if (xfontset && !JNU_IsNull(env, xfsname))
262 JNU_ReleaseStringPlatformChars(env, xfsname, (const char *) xfontset);
263
264 (*env)->DeleteLocalRef(env, peer);
265 (*env)->DeleteLocalRef(env, xfsname);
266 return xfs;
267}
268
269/*
270 * get multi font string width with multiple X11 font
271 *
272 * ASSUMES: We are not running on a privileged thread
273 */
274int32_t
275awtJNI_GetMFStringWidth(JNIEnv * env, jcharArray s, int offset, int sLength, jobject font)
276{
277 char *err = NULL;
278 unsigned char *stringData = NULL;
279 char *offsetStringData = NULL;
280 int32_t stringCount, i;
281 int32_t size;
282 struct FontData *fdata = NULL;
283 jobject fontDescriptor = NULL;
284 jbyteArray data = NULL;
285 int32_t j;
286 int32_t width = 0;
287 int32_t length;
288 XFontStruct *xf = NULL;
289 jobjectArray dataArray = NULL;
290 if ((*env)->EnsureLocalCapacity(env, 3) < 0)
291 return 0;
292
293 if (!JNU_IsNull(env, s) && !JNU_IsNull(env, font))
294 {
295 jobject peer;
296 peer = (*env)->CallObjectMethod(env,font,fontIDs.getPeer);
297
298 dataArray = (*env)->CallObjectMethod(
299 env,
300 peer,
301 platformFontIDs.makeConvertedMultiFontChars,
302 s, offset, sLength);
303
304 if ((*env)->ExceptionOccurred(env))
305 {
306 (*env)->ExceptionDescribe(env);
307 (*env)->ExceptionClear(env);
308 }
309
310 (*env)->DeleteLocalRef(env, peer);
311
312 if(dataArray == NULL)
313 {
314 return 0;
315 }
316 } else {
317 return 0;
318 }
319
320 fdata = awtJNI_GetFontData(env, font, &err);
321 if ((*env)->ExceptionCheck(env)) {
322 (*env)->DeleteLocalRef(env, dataArray);
323 return 0;
324 }
325
326 stringCount = (*env)->GetArrayLength(env, dataArray);
327
328 size = (*env)->GetIntField(env, font, fontIDs.size);
329
330 for (i = 0; i < stringCount; i+=2)
331 {
332 fontDescriptor = (*env)->GetObjectArrayElement(env, dataArray, i);
333 data = (*env)->GetObjectArrayElement(env, dataArray, i + 1);
334
335 /* Bail if we've finished */
336 if (fontDescriptor == NULL || data == NULL) {
337 (*env)->DeleteLocalRef(env, fontDescriptor);
338 (*env)->DeleteLocalRef(env, data);
339 break;
340 }
341
342 j = awtJNI_GetFontDescriptorNumber(env, font, fontDescriptor);
343 if ((*env)->ExceptionCheck(env)) {
344 (*env)->DeleteLocalRef(env, fontDescriptor);
345 (*env)->DeleteLocalRef(env, data);
346 break;
347 }
348
349 if (fdata->flist[j].load == 0) {
350 xf = loadFont(awt_display,
351 fdata->flist[j].xlfd, size * 10);
352 if (xf == NULL) {
353 (*env)->DeleteLocalRef(env, fontDescriptor);
354 (*env)->DeleteLocalRef(env, data);
355 continue;
356 }
357 fdata->flist[j].load = 1;
358 fdata->flist[j].xfont = xf;
359 if (xf->min_byte1 == 0 && xf->max_byte1 == 0)
360 fdata->flist[j].index_length = 1;
361 else
362 fdata->flist[j].index_length = 2;
363 }
364 xf = fdata->flist[j].xfont;
365
366 stringData =
367 (unsigned char *)(*env)->GetPrimitiveArrayCritical(env, data,NULL);
368 if (stringData == NULL) {
369 (*env)->DeleteLocalRef(env, fontDescriptor);
370 (*env)->DeleteLocalRef(env, data);
371 (*env)->ExceptionClear(env);
372 JNU_ThrowOutOfMemoryError(env, "Could not get string data");
373 break;
374 }
375
376 length = (stringData[0] << 24) | (stringData[1] << 16) |
377 (stringData[2] << 8) | stringData[3];
378 offsetStringData = (char *)(stringData + (4 * sizeof(char)));
379
380 if (fdata->flist[j].index_length == 2) {
381 width += XTextWidth16(xf, (XChar2b *)offsetStringData, length/2);
382 } else {
383 width += XTextWidth(xf, offsetStringData, length);
384 }
385
386 (*env)->ReleasePrimitiveArrayCritical(env, data, stringData, JNI_ABORT);
387 (*env)->DeleteLocalRef(env, fontDescriptor);
388 (*env)->DeleteLocalRef(env, data);
389 }
390 (*env)->DeleteLocalRef(env, dataArray);
391
392 return width;
393}
394