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