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 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 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 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 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 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 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 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 }