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 NSArray* 197 GetFilteredFonts() 198 { 199 if (sFilteredFonts == nil) { 200 NSFontManager *fontManager = [NSFontManager sharedFontManager]; 201 NSUInteger fontCount = [[fontManager availableFonts] count]; 202 203 NSMutableArray *allFonts = [[NSMutableArray alloc] initWithCapacity:fontCount]; 204 NSMutableDictionary* fontFamilyTable = [[NSMutableDictionary alloc] initWithCapacity:fontCount]; 205 NSArray *allFamilies = [fontManager availableFontFamilies]; 206 207 NSUInteger familyCount = [allFamilies count]; 208 209 NSUInteger familyIndex; 210 for (familyIndex = 0; familyIndex < familyCount; familyIndex++) { 211 NSString *family = [allFamilies objectAtIndex:familyIndex]; 212 213 if ((family == nil) || [family characterAtIndex:0] == '.') { 214 continue; 215 } 216 217 NSArray *fontFaces = [fontManager availableMembersOfFontFamily:family]; 218 NSUInteger faceCount = [fontFaces count]; 219 220 NSUInteger faceIndex; 221 for (faceIndex = 0; faceIndex < faceCount; faceIndex++) { 222 NSString* face = [[fontFaces objectAtIndex:faceIndex] objectAtIndex:0]; 223 if (face != nil) { 224 [allFonts addObject:face]; 225 [fontFamilyTable setObject:family forKey:face]; 226 } 227 } 228 } 229 230 sFilteredFonts = allFonts; 231 sFontFamilyTable = fontFamilyTable; 232 } 233 234 return sFilteredFonts; 235 } 236 237 #pragma mark --- sun.font.CFontManager JNI --- 238 239 static OSStatus CreateFSRef(FSRef *myFSRefPtr, NSString *inPath) 240 { 241 return FSPathMakeRef((UInt8 *)[inPath fileSystemRepresentation], 242 myFSRefPtr, NULL); 243 } 244 245 // /* 246 // * Class: sun_font_CFontManager 247 // * Method: loadFileFont 248 // * Signature: (Ljava/lang/String;)Lsun/font/Font2D; 249 // */ 250 // JNIEXPORT /* sun.font.CFont */ jobject JNICALL 251 // Java_sun_font_CFontManager_loadFileFont 252 // (JNIEnv *env, jclass obj, jstring fontpath) 253 // { 254 // jobject result = NULL; 255 // 256 // JNF_COCOA_ENTER(env); 257 // 258 // NSString *nsFilePath = JNFJavaToNSString(env, fontpath); 259 // jstring javaFontName = NULL; 260 // 261 // // 262 // // Note: This API uses ATS and can therefore return Carbon error codes. 263 // // These codes can be found at: 264 // // http://developer.apple.com/techpubs/macosx/Carbon/Files/FileManager/File_Manager/ResultCodes/ResultCodes.html 265 // // 266 // 267 // FSRef iFile; 268 // OSStatus status = CreateFSRef(&iFile, nsFilePath); 269 // 270 // if (status == noErr) { 271 // ATSFontContainerRef oContainer; 272 // status = ATSFontActivateFromFileReference(&iFile, kATSFontContextLocal, 273 // kATSFontFormatUnspecified, 274 // NULL, 275 // kATSOptionFlagsUseDataFork, 276 // &oContainer); 277 // if (status == noErr) { 278 // ATSFontRef ioArray[1]; 279 // ItemCount oCount; 280 // status = ATSFontFindFromContainer(oContainer, 281 // kATSOptionFlagsUseDataFork, 282 // 1, ioArray, &oCount); 283 // 284 // if (status == noErr) { 285 // CFStringRef oName; 286 // status = ATSFontGetPostScriptName(ioArray[0], 287 // kATSOptionFlagsUseDataFork, 288 // &oName); 289 // if (status == noErr) { 290 // javaFontName = JNFNSToJavaString(env, (NSString *)oName); 291 // CFRelease(oName); 292 // } 293 // } 294 // } 295 // } 296 // 297 // if (javaFontName != NULL) { 298 // // create the CFont! 299 // static JNF_CLASS_CACHE(sjc_CFont, "sun/font/CFont"); 300 // static JNF_CTOR_CACHE(sjf_CFont_ctor, 301 // sjc_CFont, "(Ljava/lang/String;)V"); 302 // result = JNFNewObject(env, sjf_CFont_ctor, javaFontName); 303 // } 304 // 305 // JNF_COCOA_EXIT(env); 306 // 307 // return result; 308 // } 309 310 /* 311 * Class: sun_font_CFontManager 312 * Method: loadNativeFonts 313 * Signature: ()V 314 */ 315 JNIEXPORT void JNICALL 316 Java_sun_font_CFontManager_loadNativeFonts 317 (JNIEnv *env, jobject jthis) 318 { 319 static JNF_CLASS_CACHE(jc_CFontManager, 320 "sun/font/CFontManager"); 321 static JNF_MEMBER_CACHE(jm_registerFont, jc_CFontManager, 322 "registerFont", 323 "(Ljava/lang/String;Ljava/lang/String;)V"); 324 325 jint num = 0; 326 327 JNF_COCOA_ENTER(env); 328 329 NSArray *filteredFonts = GetFilteredFonts(); 330 num = (jint)[filteredFonts count]; 331 332 jint i; 333 for (i = 0; i < num; i++) { 334 NSString *fontname = [filteredFonts objectAtIndex:i]; 335 jobject jFontName = JNFNSToJavaString(env, fontname); 336 jobject jFontFamilyName = 337 JNFNSToJavaString(env, GetFamilyNameForFontName(fontname)); 338 339 JNFCallVoidMethod(env, jthis, 340 jm_registerFont, jFontName, jFontFamilyName); 341 (*env)->DeleteLocalRef(env, jFontName); 342 (*env)->DeleteLocalRef(env, jFontFamilyName); 343 } 344 345 JNF_COCOA_EXIT(env); 346 } 347 348 /* 349 * Class: Java_sun_font_CFontManager_loadNativeDirFonts 350 * Method: loadNativeDirFonts 351 * Signature: (Ljava/lang/String;)V; 352 */ 353 JNIEXPORT void JNICALL 354 Java_sun_font_CFontManager_loadNativeDirFonts 355 (JNIEnv *env, jclass clz, jstring filename) 356 { 357 JNF_COCOA_ENTER(env); 358 359 NSString *nsFilePath = JNFJavaToNSString(env, filename); 360 361 FSRef iFile; 362 OSStatus status = CreateFSRef(&iFile, nsFilePath); 363 364 if (status == noErr) { 365 ATSFontContainerRef oContainer; 366 status = ATSFontActivateFromFileReference(&iFile, kATSFontContextLocal, 367 kATSFontFormatUnspecified, 368 NULL, kNilOptions, 369 &oContainer); 370 } 371 372 JNF_COCOA_EXIT(env); 373 } 374 375 #pragma mark --- sun.font.CFont JNI --- 376 377 /* 378 * Class: sun_font_CFont 379 * Method: getPlatformFontPtrNative 380 * Signature: (JI)[B 381 */ 382 JNIEXPORT jlong JNICALL 383 Java_sun_font_CFont_getCGFontPtrNative 384 (JNIEnv *env, jclass clazz, 385 jlong awtFontPtr) 386 { 387 AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); 388 return (jlong)(awtFont->fNativeCGFont); 389 } 390 391 /* 392 * Class: sun_font_CFont 393 * Method: getLayoutTableCacheNative 394 * Signature: (J)J 395 */ 396 JNIEXPORT jlong JNICALL 397 Java_sun_font_CFont_getLayoutTableCacheNative 398 (JNIEnv *env, jclass clazz, 399 jlong awtFontPtr) 400 { 401 AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); 402 if (awtFont->layoutTableCache == NULL) { 403 awtFont->layoutTableCache = newCFontLayoutTableCache(); 404 } 405 return (jlong)(awtFont->layoutTableCache); 406 } 407 408 /* 409 * Class: sun_font_CFont 410 * Method: getTableBytesNative 411 * Signature: (JI)[B 412 */ 413 JNIEXPORT jbyteArray JNICALL 414 Java_sun_font_CFont_getTableBytesNative 415 (JNIEnv *env, jclass clazz, 416 jlong awtFontPtr, jint jtag) 417 { 418 jbyteArray jbytes = NULL; 419 JNF_COCOA_ENTER(env); 420 421 CTFontTableTag tag = (CTFontTableTag)jtag; 422 int i, found = 0; 423 AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); 424 NSFont* nsFont = awtFont->fFont; 425 CTFontRef ctfont = (CTFontRef)nsFont; 426 CFArrayRef tagsArray = 427 CTFontCopyAvailableTables(ctfont, kCTFontTableOptionNoOptions); 428 CFIndex numTags = CFArrayGetCount(tagsArray); 429 for (i=0; i<numTags; i++) { 430 if (tag == 431 (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tagsArray, i)) { 432 found = 1; 433 break; 434 } 435 } 436 CFRelease(tagsArray); 437 if (!found) { 438 return NULL; 439 } 440 CFDataRef table = CTFontCopyTable(ctfont, tag, kCTFontTableOptionNoOptions); 441 if (table == NULL) { 442 return NULL; 443 } 444 445 char *tableBytes = (char*)(CFDataGetBytePtr(table)); 446 size_t tableLength = CFDataGetLength(table); 447 if (tableBytes == NULL || tableLength == 0) { 448 CFRelease(table); 449 return NULL; 450 } 451 452 jbytes = (*env)->NewByteArray(env, (jsize)tableLength); 453 if (jbytes == NULL) { 454 return NULL; 455 } 456 (*env)->SetByteArrayRegion(env, jbytes, 0, 457 (jsize)tableLength, 458 (jbyte*)tableBytes); 459 CFRelease(table); 460 461 JNF_COCOA_EXIT(env); 462 463 return jbytes; 464 } 465 466 /* 467 * Class: sun_font_CFont 468 * Method: initNativeFont 469 * Signature: (Ljava/lang/String;I)J 470 */ 471 JNIEXPORT jlong JNICALL 472 Java_sun_font_CFont_createNativeFont 473 (JNIEnv *env, jclass clazz, 474 jstring nativeFontName, jint style) 475 { 476 AWTFont *awtFont = nil; 477 478 JNF_COCOA_ENTER(env); 479 480 awtFont = 481 [AWTFont awtFontForName:JNFJavaToNSString(env, nativeFontName) 482 style:style]; // autoreleased 483 484 if (awtFont) { 485 CFRetain(awtFont); // GC 486 } 487 488 JNF_COCOA_EXIT(env); 489 490 return ptr_to_jlong(awtFont); 491 } 492 493 /* 494 * Class: sun_font_CFont 495 * Method: getWidthNative 496 * Signature: (J)F 497 */ 498 JNIEXPORT jfloat JNICALL 499 Java_sun_font_CFont_getWidthNative 500 (JNIEnv *env, jobject cfont, jlong awtFontPtr) 501 { 502 float widthVal; 503 JNF_COCOA_ENTER(env); 504 505 AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); 506 NSFont* nsFont = awtFont->fFont; 507 NSFontDescriptor *fontDescriptor = nsFont.fontDescriptor; 508 NSDictionary *fontTraits = [fontDescriptor objectForKey : NSFontTraitsAttribute]; 509 NSNumber *width = [fontTraits objectForKey : NSFontWidthTrait]; 510 widthVal = (float)[width floatValue]; 511 512 JNF_COCOA_EXIT(env); 513 return (jfloat)widthVal; 514 } 515 516 /* 517 * Class: sun_font_CFont 518 * Method: getWeightNative 519 * Signature: (J)F 520 */ 521 JNIEXPORT jfloat JNICALL 522 Java_sun_font_CFont_getWeightNative 523 (JNIEnv *env, jobject cfont, jlong awtFontPtr) 524 { 525 float weightVal; 526 JNF_COCOA_ENTER(env); 527 528 AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); 529 NSFont* nsFont = awtFont->fFont; 530 NSFontDescriptor *fontDescriptor = nsFont.fontDescriptor; 531 NSDictionary *fontTraits = [fontDescriptor objectForKey : NSFontTraitsAttribute]; 532 NSNumber *weight = [fontTraits objectForKey : NSFontWeightTrait]; 533 weightVal = (float)[weight floatValue]; 534 535 JNF_COCOA_EXIT(env); 536 return (jfloat)weightVal; 537 } 538 539 /* 540 * Class: sun_font_CFont 541 * Method: disposeNativeFont 542 * Signature: (J)V 543 */ 544 JNIEXPORT void JNICALL 545 Java_sun_font_CFont_disposeNativeFont 546 (JNIEnv *env, jclass clazz, jlong awtFontPtr) 547 { 548 JNF_COCOA_ENTER(env); 549 550 if (awtFontPtr) { 551 CFRelease((AWTFont *)jlong_to_ptr(awtFontPtr)); // GC 552 } 553 554 JNF_COCOA_EXIT(env); 555 } 556 557 558 #pragma mark --- Miscellaneous JNI --- 559 560 #ifndef HEADLESS 561 /* 562 * Class: sun_awt_PlatformFont 563 * Method: initIDs 564 * Signature: ()V 565 */ 566 JNIEXPORT void JNICALL 567 Java_sun_awt_PlatformFont_initIDs 568 (JNIEnv *env, jclass cls) 569 { 570 } 571 572 /* 573 * Class: sun_awt_FontDescriptor 574 * Method: initIDs 575 * Signature: ()V 576 */ 577 JNIEXPORT void JNICALL 578 Java_sun_awt_FontDescriptor_initIDs 579 (JNIEnv *env, jclass cls) 580 { 581 } 582 #endif 583 584 /* 585 * Class: sun_awt_FontDescriptor 586 * Method: initIDs 587 * Signature: ()V 588 */ 589 JNIEXPORT void JNICALL 590 Java_sun_font_CFont_getCascadeList 591 (JNIEnv *env, jclass cls, jlong awtFontPtr, jobject arrayListOfString) 592 { 593 jclass alc = (*env)->FindClass(env, "java/util/ArrayList"); 594 if (alc == NULL) return; 595 jmethodID addMID = (*env)->GetMethodID(env, alc, "add", "(Ljava/lang/Object;)Z"); 596 if (addMID == NULL) return; 597 598 CFIndex i; 599 AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); 600 NSFont* nsFont = awtFont->fFont; 601 CTFontRef font = (CTFontRef)nsFont; 602 CFStringRef base = CTFontCopyFullName(font); 603 CFArrayRef codes = CFLocaleCopyISOLanguageCodes(); 604 605 #ifdef DEBUG 606 NSLog(@"BaseFont is : %@", (NSString*)base); 607 #endif 608 CFArrayRef fds = CTFontCopyDefaultCascadeListForLanguages(font, codes); 609 CFIndex cnt = CFArrayGetCount(fds); 610 for (i=0; i<cnt; i++) { 611 CTFontDescriptorRef ref = CFArrayGetValueAtIndex(fds, i); 612 CFStringRef fontname = 613 CTFontDescriptorCopyAttribute(ref, kCTFontNameAttribute); 614 #ifdef DEBUG 615 NSLog(@"Font is : %@", (NSString*)fontname); 616 #endif 617 jstring jFontName = (jstring)JNFNSToJavaString(env, fontname); 618 (*env)->CallBooleanMethod(env, arrayListOfString, addMID, jFontName); 619 (*env)->DeleteLocalRef(env, jFontName); 620 } 621 }