src/java.desktop/unix/native/libawt_xawt/awt/multi_font.c
changeset 57515 2db64810f4fc
parent 55374 5c4f1b7c753b
child 57516 fe5395d16475
equal deleted inserted replaced
55374:5c4f1b7c753b 57515:2db64810f4fc
     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 }