1 /*
   2  * Copyright (c) 2011, 2013, 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 #import <JavaNativeFoundation/JavaNativeFoundation.h>
  27 
  28 #import "java_awt_Font.h"
  29 #import "sun_awt_PlatformFont.h"
  30 #import "sun_awt_FontDescriptor.h"
  31 #import "sun_font_CFont.h"
  32 #import "sun_font_CFontManager.h"
  33 
  34 #import "AWTFont.h"
  35 #import "AWTStrike.h"
  36 #import "CoreTextSupport.h"
  37 
  38 @implementation AWTFont
  39 
  40 - (id) initWithFont:(NSFont *)font {
  41     self = [super init];
  42     if (self) {
  43         fFont = [font retain];
  44         fNativeCGFont = CTFontCopyGraphicsFont((CTFontRef)font, NULL);
  45         layoutTableCache = NULL;
  46     }
  47     return self;
  48 }
  49 
  50 static TTLayoutTableCache* newCFontLayoutTableCache() {
  51   TTLayoutTableCache* ltc = calloc(1, sizeof(TTLayoutTableCache));
  52   if (ltc) {
  53     int i;
  54     for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
  55       ltc->entries[i].len = -1;
  56     }
  57   }
  58   return ltc;
  59 }
  60 
  61 static void freeCFontLayoutTableCache(TTLayoutTableCache* ltc) {
  62   if (ltc) {
  63     int i;
  64     for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
  65       if(ltc->entries[i].ptr) free (ltc->entries[i].ptr);
  66     }
  67     if (ltc->kernPairs) free(ltc->kernPairs);
  68     free(ltc);
  69   }
  70 }
  71 
  72 - (void) dealloc {
  73     [fFont release];
  74     fFont = nil;
  75 
  76     if (fNativeCGFont) {
  77         CGFontRelease(fNativeCGFont);
  78     fNativeCGFont = NULL;
  79     if (layoutTableCache != NULL) {
  80         freeCFontLayoutTableCache(layoutTableCache);
  81         layoutTableCache = NULL;
  82     }
  83     }
  84 
  85     [super dealloc];
  86 }
  87 
  88 - (void) finalize {
  89     if (fNativeCGFont) {
  90         CGFontRelease(fNativeCGFont);
  91     fNativeCGFont = NULL;
  92     }
  93     if (layoutTableCache != NULL) {
  94         freeCFontLayoutTableCache(layoutTableCache);
  95         layoutTableCache = NULL;
  96     }
  97     [super finalize];
  98 }
  99 
 100 + (AWTFont *) awtFontForName:(NSString *)name
 101                        style:(int)style
 102 {
 103     // create font with family & size
 104     NSFont *nsFont = [NSFont fontWithName:name size:1.0];
 105 
 106     if (nsFont == nil) {
 107         // if can't get font of that name, substitute system default font
 108         nsFont = [NSFont fontWithName:@"Lucida Grande" size:1.0];
 109 #ifdef DEBUG
 110         NSLog(@"needed to substitute Lucida Grande for: %@", name);
 111 #endif
 112     }
 113 
 114     // create an italic style (if one is installed)
 115     if (style & java_awt_Font_ITALIC) {
 116         nsFont = [[NSFontManager sharedFontManager] convertFont:nsFont toHaveTrait:NSItalicFontMask];
 117     }
 118 
 119     // create a bold style (if one is installed)
 120     if (style & java_awt_Font_BOLD) {
 121         nsFont = [[NSFontManager sharedFontManager] convertFont:nsFont toHaveTrait:NSBoldFontMask];
 122     }
 123 
 124     return [[[AWTFont alloc] initWithFont:nsFont] autorelease];
 125 }
 126 
 127 + (NSFont *) nsFontForJavaFont:(jobject)javaFont env:(JNIEnv *)env {
 128     if (javaFont == NULL) {
 129 #ifdef DEBUG
 130         NSLog(@"nil font");
 131 #endif
 132         return nil;
 133     }
 134 
 135     static JNF_CLASS_CACHE(jc_Font, "java/awt/Font");
 136 
 137     // obtain the Font2D
 138     static JNF_MEMBER_CACHE(jm_Font_getFont2D, jc_Font, "getFont2D", "()Lsun/font/Font2D;");
 139     jobject font2d = JNFCallObjectMethod(env, javaFont, jm_Font_getFont2D);
 140     if (font2d == NULL) {
 141 #ifdef DEBUG
 142         NSLog(@"nil font2d");
 143 #endif
 144         return nil;
 145     }
 146 
 147     // if it's not a CFont, it's likely one of TTF or OTF fonts
 148     // from the Sun rendering loops
 149     static JNF_CLASS_CACHE(jc_CFont, "sun/font/CFont");
 150     if (!JNFIsInstanceOf(env, font2d, &jc_CFont)) {
 151 #ifdef DEBUG
 152         NSLog(@"font2d !instanceof CFont");
 153 #endif
 154         return nil;
 155     }
 156 
 157     static JNF_MEMBER_CACHE(jm_CFont_getFontStrike, jc_CFont, "getStrike", "(Ljava/awt/Font;)Lsun/font/FontStrike;");
 158     jobject fontStrike = JNFCallObjectMethod(env, font2d, jm_CFont_getFontStrike, javaFont);
 159 
 160     static JNF_CLASS_CACHE(jc_CStrike, "sun/font/CStrike");
 161     if (!JNFIsInstanceOf(env, fontStrike, &jc_CStrike)) {
 162 #ifdef DEBUG
 163         NSLog(@"fontStrike !instanceof CStrike");
 164 #endif
 165         return nil;
 166     }
 167 
 168     static JNF_MEMBER_CACHE(jm_CStrike_nativeStrikePtr, jc_CStrike, "getNativeStrikePtr", "()J");
 169     jlong awtStrikePtr = JNFCallLongMethod(env, fontStrike, jm_CStrike_nativeStrikePtr);
 170     if (awtStrikePtr == 0L) {
 171 #ifdef DEBUG
 172         NSLog(@"nil nativeFontPtr from CFont");
 173 #endif
 174         return nil;
 175     }
 176 
 177     AWTStrike *strike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
 178 
 179     return [NSFont fontWithName:[strike->fAWTFont->fFont fontName] matrix:(CGFloat *)(&(strike->fAltTx))];
 180 }
 181 
 182 @end
 183 
 184 
 185 #pragma mark --- Font Discovery and Loading ---
 186 
 187 static NSArray* sFilteredFonts = nil;
 188 static NSDictionary* sFontFamilyTable = nil;
 189 
 190 static NSString*
 191 GetFamilyNameForFontName(NSString* fontname)
 192 {
 193     return [sFontFamilyTable objectForKey:fontname];
 194 }
 195 
 196 static void addFont(CTFontUIFontType uiType, 
 197                     NSMutableArray *allFonts,
 198                     NSMutableDictionary* fontFamilyTable) {
 199 
 200         CTFontRef font = CTFontCreateUIFontForLanguage(uiType, 0.0, NULL);
 201         if (font == NULL) {
 202             return;
 203         }
 204         CTFontDescriptorRef desc = CTFontCopyFontDescriptor(font);
 205         if (desc == NULL) {
 206             CFRelease(font);
 207             return;
 208         }
 209         CFStringRef family = CTFontDescriptorCopyAttribute(desc, kCTFontFamilyNameAttribute);
 210         if (family == NULL) {
 211             CFRelease(font);
 212             CFRelease(desc);
 213             return;
 214         }
 215         CFStringRef name = CTFontDescriptorCopyAttribute(desc, kCTFontNameAttribute);
 216         if (name == NULL) {
 217             CFRelease(family);
 218             CFRelease(font);
 219             CFRelease(desc);
 220             return;
 221         }
 222         [allFonts addObject:name];
 223         [fontFamilyTable setObject:family forKey:name];
 224 #ifdef DEBUG
 225         NSLog(@"name is : %@", (NSString*)name);
 226         NSLog(@"family is : %@", (NSString*)family);
 227 #endif
 228         CFRelease(family);
 229         CFRelease(name);
 230         CFRelease(desc);
 231         CFRelease(font);
 232 }
 233  
 234 static NSArray*
 235 GetFilteredFonts()
 236 {
 237     if (sFilteredFonts == nil) {
 238         NSFontManager *fontManager = [NSFontManager sharedFontManager];
 239         NSUInteger fontCount = [[fontManager availableFonts] count];
 240 
 241         NSMutableArray *allFonts = [[NSMutableArray alloc] initWithCapacity:fontCount];
 242         NSMutableDictionary* fontFamilyTable = [[NSMutableDictionary alloc] initWithCapacity:fontCount];
 243         NSArray *allFamilies = [fontManager availableFontFamilies];
 244 
 245         NSUInteger familyCount = [allFamilies count];
 246 
 247         NSUInteger familyIndex;
 248         for (familyIndex = 0; familyIndex < familyCount; familyIndex++) {
 249             NSString *family = [allFamilies objectAtIndex:familyIndex];
 250 
 251             if ((family == nil) || [family characterAtIndex:0] == '.') {
 252                 continue;
 253             }
 254 
 255             NSArray *fontFaces = [fontManager availableMembersOfFontFamily:family];
 256             NSUInteger faceCount = [fontFaces count];
 257 
 258             NSUInteger faceIndex;
 259             for (faceIndex = 0; faceIndex < faceCount; faceIndex++) {
 260                 NSString* face = [[fontFaces objectAtIndex:faceIndex] objectAtIndex:0];
 261                 if (face != nil) {
 262                     [allFonts addObject:face];
 263                     [fontFamilyTable setObject:family forKey:face];
 264                 }
 265             }
 266         }
 267 
 268         /*
 269          * JavaFX registers these fonts and so JDK needs to do so as well.
 270          * If this isn't done we will have mis-matched rendering, since
 271          * although these may include fonts that are enumerated normally
 272          * they also demonstrably includes fonts that are not.
 273          */
 274         addFont(kCTFontUIFontSystem, allFonts, fontFamilyTable);
 275         addFont(kCTFontUIFontEmphasizedSystem, allFonts, fontFamilyTable);
 276         addFont(kCTFontUIFontUserFixedPitch, allFonts, fontFamilyTable);
 277 
 278         sFilteredFonts = allFonts;
 279         sFontFamilyTable = fontFamilyTable;
 280     }
 281 
 282     return sFilteredFonts;
 283 }
 284 
 285 #pragma mark --- sun.font.CFontManager JNI ---
 286 
 287 static OSStatus CreateFSRef(FSRef *myFSRefPtr, NSString *inPath)
 288 {
 289     return FSPathMakeRef((UInt8 *)[inPath fileSystemRepresentation],
 290                          myFSRefPtr, NULL);
 291 }
 292 
 293 // /*
 294 //  * Class:     sun_font_CFontManager
 295 //  * Method:    loadFileFont
 296 //  * Signature: (Ljava/lang/String;)Lsun/font/Font2D;
 297 //  */
 298 // JNIEXPORT /* sun.font.CFont */ jobject JNICALL
 299 // Java_sun_font_CFontManager_loadFileFont
 300 //     (JNIEnv *env, jclass obj, jstring fontpath)
 301 // {
 302 //     jobject result = NULL;
 303 //
 304 // JNF_COCOA_ENTER(env);
 305 //
 306 //     NSString *nsFilePath = JNFJavaToNSString(env, fontpath);
 307 //     jstring javaFontName = NULL;
 308 //
 309 //     //
 310 //     // Note: This API uses ATS and can therefore return Carbon error codes.
 311 //     // These codes can be found at:
 312 //     // http://developer.apple.com/techpubs/macosx/Carbon/Files/FileManager/File_Manager/ResultCodes/ResultCodes.html
 313 //     //
 314 //
 315 //     FSRef iFile;
 316 //     OSStatus status = CreateFSRef(&iFile, nsFilePath);
 317 //
 318 //     if (status == noErr) {
 319 //         ATSFontContainerRef oContainer;
 320 //         status = ATSFontActivateFromFileReference(&iFile, kATSFontContextLocal,
 321 //                                                   kATSFontFormatUnspecified,
 322 //                                                   NULL,
 323 //                                                   kATSOptionFlagsUseDataFork,
 324 //                                                   &oContainer);
 325 //         if (status == noErr) {
 326 //             ATSFontRef ioArray[1];
 327 //             ItemCount oCount;
 328 //             status = ATSFontFindFromContainer(oContainer,
 329 //                                               kATSOptionFlagsUseDataFork,
 330 //                                               1, ioArray, &oCount);
 331 //
 332 //             if (status == noErr) {
 333 //                 CFStringRef oName;
 334 //                 status = ATSFontGetPostScriptName(ioArray[0],
 335 //                                                   kATSOptionFlagsUseDataFork,
 336 //                                                   &oName);
 337 //                 if (status == noErr) {
 338 //                     javaFontName = JNFNSToJavaString(env, (NSString *)oName);
 339 //                     CFRelease(oName);
 340 //                 }
 341 //             }
 342 //         }
 343 //     }
 344 //
 345 //     if (javaFontName != NULL) {
 346 //         // create the CFont!
 347 //         static JNF_CLASS_CACHE(sjc_CFont, "sun/font/CFont");
 348 //         static JNF_CTOR_CACHE(sjf_CFont_ctor,
 349 //                               sjc_CFont, "(Ljava/lang/String;)V");
 350 //         result = JNFNewObject(env, sjf_CFont_ctor, javaFontName);
 351 //     }
 352 //
 353 // JNF_COCOA_EXIT(env);
 354 //
 355 //     return result;
 356 // }
 357 
 358 /*
 359  * Class:     sun_font_CFontManager
 360  * Method:    loadNativeFonts
 361  * Signature: ()V
 362  */
 363 JNIEXPORT void JNICALL
 364 Java_sun_font_CFontManager_loadNativeFonts
 365     (JNIEnv *env, jobject jthis)
 366 {
 367     static JNF_CLASS_CACHE(jc_CFontManager,
 368                            "sun/font/CFontManager");
 369     static JNF_MEMBER_CACHE(jm_registerFont, jc_CFontManager,
 370                             "registerFont",
 371                             "(Ljava/lang/String;Ljava/lang/String;)V");
 372 
 373     jint num = 0;
 374 
 375 JNF_COCOA_ENTER(env);
 376 
 377     NSArray *filteredFonts = GetFilteredFonts();
 378     num = (jint)[filteredFonts count];
 379 
 380     jint i;
 381     for (i = 0; i < num; i++) {
 382         NSString *fontname = [filteredFonts objectAtIndex:i];
 383         jobject jFontName = JNFNSToJavaString(env, fontname);
 384         jobject jFontFamilyName =
 385             JNFNSToJavaString(env, GetFamilyNameForFontName(fontname));
 386 
 387         JNFCallVoidMethod(env, jthis,
 388                           jm_registerFont, jFontName, jFontFamilyName);
 389         (*env)->DeleteLocalRef(env, jFontName);
 390         (*env)->DeleteLocalRef(env, jFontFamilyName);
 391     }
 392 
 393 JNF_COCOA_EXIT(env);
 394 }
 395 
 396 /*
 397  * Class:     Java_sun_font_CFontManager_loadNativeDirFonts
 398  * Method:    loadNativeDirFonts
 399  * Signature: (Ljava/lang/String;)V;
 400  */
 401 JNIEXPORT void JNICALL
 402 Java_sun_font_CFontManager_loadNativeDirFonts
 403 (JNIEnv *env, jclass clz, jstring filename)
 404 {
 405 JNF_COCOA_ENTER(env);
 406 
 407     NSString *nsFilePath = JNFJavaToNSString(env, filename);
 408 
 409     FSRef iFile;
 410     OSStatus status = CreateFSRef(&iFile, nsFilePath);
 411 
 412     if (status == noErr) {
 413         ATSFontContainerRef oContainer;
 414         status = ATSFontActivateFromFileReference(&iFile, kATSFontContextLocal,
 415                                                   kATSFontFormatUnspecified,
 416                                                   NULL, kNilOptions,
 417                                                   &oContainer);
 418     }
 419 
 420 JNF_COCOA_EXIT(env);
 421 }
 422 
 423 #pragma mark --- sun.font.CFont JNI ---
 424 
 425 /*
 426  * Class:     sun_font_CFont
 427  * Method:    getPlatformFontPtrNative
 428  * Signature: (JI)[B
 429  */
 430 JNIEXPORT jlong JNICALL
 431 Java_sun_font_CFont_getCGFontPtrNative
 432     (JNIEnv *env, jclass clazz,
 433      jlong awtFontPtr)
 434 {
 435     AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
 436     return (jlong)(awtFont->fNativeCGFont);
 437 }
 438 
 439 /*
 440  * Class:     sun_font_CFont
 441  * Method:    getLayoutTableCacheNative
 442  * Signature: (J)J
 443  */
 444 JNIEXPORT jlong JNICALL
 445 Java_sun_font_CFont_getLayoutTableCacheNative
 446     (JNIEnv *env, jclass clazz,
 447      jlong awtFontPtr)
 448 {
 449     AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
 450     if (awtFont->layoutTableCache == NULL) {
 451         awtFont->layoutTableCache = newCFontLayoutTableCache();
 452     }
 453     return (jlong)(awtFont->layoutTableCache);
 454 }
 455 
 456 /*
 457  * Class:     sun_font_CFont
 458  * Method:    getTableBytesNative
 459  * Signature: (JI)[B
 460  */
 461 JNIEXPORT jbyteArray JNICALL
 462 Java_sun_font_CFont_getTableBytesNative
 463     (JNIEnv *env, jclass clazz,
 464      jlong awtFontPtr, jint jtag)
 465 {
 466     jbyteArray jbytes = NULL;
 467 JNF_COCOA_ENTER(env);
 468 
 469     CTFontTableTag tag = (CTFontTableTag)jtag;
 470     int i, found = 0;
 471     AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
 472     NSFont* nsFont = awtFont->fFont;
 473     CTFontRef ctfont = (CTFontRef)nsFont;
 474     CFArrayRef tagsArray =
 475         CTFontCopyAvailableTables(ctfont, kCTFontTableOptionNoOptions);
 476     CFIndex numTags = CFArrayGetCount(tagsArray);
 477     for (i=0; i<numTags; i++) {
 478         if (tag ==
 479             (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tagsArray, i)) {
 480             found = 1;
 481             break;
 482         }
 483     }
 484     CFRelease(tagsArray);
 485     if (!found) {
 486         return NULL;
 487     }
 488     CFDataRef table = CTFontCopyTable(ctfont, tag, kCTFontTableOptionNoOptions);
 489     if (table == NULL) {
 490         return NULL;
 491     }
 492 
 493     char *tableBytes = (char*)(CFDataGetBytePtr(table));
 494     size_t tableLength = CFDataGetLength(table);
 495     if (tableBytes == NULL || tableLength == 0) {
 496         CFRelease(table);
 497         return NULL;
 498     }
 499 
 500     jbytes = (*env)->NewByteArray(env, (jsize)tableLength);
 501     if (jbytes == NULL) {
 502         return NULL;
 503     }
 504     (*env)->SetByteArrayRegion(env, jbytes, 0,
 505                                (jsize)tableLength,
 506                                (jbyte*)tableBytes);
 507     CFRelease(table);
 508 
 509 JNF_COCOA_EXIT(env);
 510 
 511     return jbytes;
 512 }
 513 
 514 /*
 515  * Class:     sun_font_CFont
 516  * Method:    initNativeFont
 517  * Signature: (Ljava/lang/String;I)J
 518  */
 519 JNIEXPORT jlong JNICALL
 520 Java_sun_font_CFont_createNativeFont
 521     (JNIEnv *env, jclass clazz,
 522      jstring nativeFontName, jint style)
 523 {
 524     AWTFont *awtFont = nil;
 525 
 526 JNF_COCOA_ENTER(env);
 527 
 528     awtFont =
 529         [AWTFont awtFontForName:JNFJavaToNSString(env, nativeFontName)
 530          style:style]; // autoreleased
 531 
 532     if (awtFont) {
 533         CFRetain(awtFont); // GC
 534     }
 535 
 536 JNF_COCOA_EXIT(env);
 537 
 538     return ptr_to_jlong(awtFont);
 539 }
 540 
 541 /*
 542  * Class:     sun_font_CFont
 543  * Method:    getWidthNative
 544  * Signature: (J)F
 545  */
 546 JNIEXPORT jfloat JNICALL
 547 Java_sun_font_CFont_getWidthNative
 548     (JNIEnv *env, jobject cfont, jlong awtFontPtr)
 549 {
 550     float widthVal;
 551 JNF_COCOA_ENTER(env);
 552 
 553     AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
 554     NSFont* nsFont = awtFont->fFont;
 555     NSFontDescriptor *fontDescriptor = nsFont.fontDescriptor;
 556     NSDictionary *fontTraits = [fontDescriptor objectForKey : NSFontTraitsAttribute];
 557     NSNumber *width = [fontTraits objectForKey : NSFontWidthTrait];
 558     widthVal = (float)[width floatValue];
 559 
 560 JNF_COCOA_EXIT(env);
 561    return (jfloat)widthVal;
 562 }
 563 
 564 /*
 565  * Class:     sun_font_CFont
 566  * Method:    getWeightNative
 567  * Signature: (J)F
 568  */
 569 JNIEXPORT jfloat JNICALL
 570 Java_sun_font_CFont_getWeightNative
 571     (JNIEnv *env, jobject cfont, jlong awtFontPtr)
 572 {
 573     float weightVal;
 574 JNF_COCOA_ENTER(env);
 575 
 576     AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
 577     NSFont* nsFont = awtFont->fFont;
 578     NSFontDescriptor *fontDescriptor = nsFont.fontDescriptor;
 579     NSDictionary *fontTraits = [fontDescriptor objectForKey : NSFontTraitsAttribute];
 580     NSNumber *weight = [fontTraits objectForKey : NSFontWeightTrait];
 581     weightVal = (float)[weight floatValue];
 582 
 583 JNF_COCOA_EXIT(env);
 584    return (jfloat)weightVal;
 585 }
 586 
 587 /*
 588  * Class:     sun_font_CFont
 589  * Method:    disposeNativeFont
 590  * Signature: (J)V
 591  */
 592 JNIEXPORT void JNICALL
 593 Java_sun_font_CFont_disposeNativeFont
 594     (JNIEnv *env, jclass clazz, jlong awtFontPtr)
 595 {
 596 JNF_COCOA_ENTER(env);
 597 
 598     if (awtFontPtr) {
 599         CFRelease((AWTFont *)jlong_to_ptr(awtFontPtr)); // GC
 600     }
 601 
 602 JNF_COCOA_EXIT(env);
 603 }
 604 
 605 
 606 #pragma mark --- Miscellaneous JNI ---
 607 
 608 #ifndef HEADLESS
 609 /*
 610  * Class:     sun_awt_PlatformFont
 611  * Method:    initIDs
 612  * Signature: ()V
 613  */
 614 JNIEXPORT void JNICALL
 615 Java_sun_awt_PlatformFont_initIDs
 616     (JNIEnv *env, jclass cls)
 617 {
 618 }
 619 
 620 /*
 621  * Class:     sun_awt_FontDescriptor
 622  * Method:    initIDs
 623  * Signature: ()V
 624  */
 625 JNIEXPORT void JNICALL
 626 Java_sun_awt_FontDescriptor_initIDs
 627     (JNIEnv *env, jclass cls)
 628 {
 629 }
 630 #endif
 631 
 632 /*
 633  * Class:     sun_awt_FontDescriptor
 634  * Method:    initIDs
 635  * Signature: ()V
 636  */
 637 JNIEXPORT void JNICALL
 638 Java_sun_font_CFont_getCascadeList
 639     (JNIEnv *env, jclass cls, jlong awtFontPtr, jobject arrayListOfString)
 640 {
 641     jclass alc = (*env)->FindClass(env, "java/util/ArrayList");
 642     if (alc == NULL) return;
 643     jmethodID addMID = (*env)->GetMethodID(env, alc, "add", "(Ljava/lang/Object;)Z");
 644     if (addMID == NULL) return;
 645 
 646     CFIndex i;
 647     AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
 648     NSFont* nsFont = awtFont->fFont;
 649     CTFontRef font = (CTFontRef)nsFont;
 650     CFStringRef base = CTFontCopyFullName(font);
 651     CFArrayRef codes = CFLocaleCopyISOLanguageCodes();
 652 
 653 #ifdef DEBUG
 654     NSLog(@"BaseFont is : %@", (NSString*)base);
 655 #endif
 656     CFArrayRef fds = CTFontCopyDefaultCascadeListForLanguages(font, codes);
 657     CFIndex cnt = CFArrayGetCount(fds);
 658     for (i=0; i<cnt; i++) {
 659         CTFontDescriptorRef ref = CFArrayGetValueAtIndex(fds, i);
 660         CFStringRef fontname =
 661             CTFontDescriptorCopyAttribute(ref, kCTFontNameAttribute);
 662 #ifdef DEBUG
 663         NSLog(@"Font is : %@", (NSString*)fontname);
 664 #endif
 665         jstring jFontName = (jstring)JNFNSToJavaString(env, fontname);
 666         (*env)->CallBooleanMethod(env, arrayListOfString, addMID, jFontName); 
 667         (*env)->DeleteLocalRef(env, jFontName);
 668     }
 669 }