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