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 
45 extern XFontStruct *loadFont(Display *, char *, int32_t);
46 
47 extern struct FontIDs fontIDs;
48 extern struct PlatformFontIDs platformFontIDs;
49 extern 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  */
55 static void
makeTag(char * str,int32_t num,char * buf)56 makeTag(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 
65 static int32_t
awtJNI_GetFontDescriptorNumber(JNIEnv * env,jobject font,jobject fd)66 awtJNI_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 
112 jobject
awtJNI_GetFMFont(JNIEnv * env,jobject this)113 awtJNI_GetFMFont(JNIEnv * env, jobject this)
114 {
115     return JNU_CallMethodByName(env, NULL, this, "getFont_NoClientCode",
116                                 "()Ljava/awt/Font;").l;
117 }
118 
119 jboolean
awtJNI_IsMultiFont(JNIEnv * env,jobject this)120 awtJNI_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 
149 jboolean
awtJNI_IsMultiFontMetrics(JNIEnv * env,jobject this)150 awtJNI_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 
188 XFontSet
awtJNI_MakeFontSet(JNIEnv * env,jobject font)189 awtJNI_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  */
274 int32_t
awtJNI_GetMFStringWidth(JNIEnv * env,jcharArray s,int offset,int sLength,jobject font)275 awtJNI_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