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