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