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 NSArray* 166 GetFilteredFonts() 167 { 168 if (sFilteredFonts == nil) { 169 NSFontManager *fontManager = [NSFontManager sharedFontManager]; 170 NSUInteger fontCount = [[fontManager availableFonts] count]; 171 172 NSMutableArray *allFonts = [[NSMutableArray alloc] initWithCapacity:fontCount]; 173 NSMutableDictionary* fontFamilyTable = [[NSMutableDictionary alloc] initWithCapacity:fontCount]; 174 NSArray *allFamilies = [fontManager availableFontFamilies]; 175 176 NSUInteger familyCount = [allFamilies count]; 177 178 NSUInteger familyIndex; 179 for (familyIndex = 0; familyIndex < familyCount; familyIndex++) { 180 NSString *family = [allFamilies objectAtIndex:familyIndex]; 181 182 if ((family == nil) || [family characterAtIndex:0] == '.') { 183 continue; 184 } 185 186 NSArray *fontFaces = [fontManager availableMembersOfFontFamily:family]; 187 NSUInteger faceCount = [fontFaces count]; 188 189 NSUInteger faceIndex; 190 for (faceIndex = 0; faceIndex < faceCount; faceIndex++) { 191 NSString* face = [[fontFaces objectAtIndex:faceIndex] objectAtIndex:0]; 192 if (face != nil) { 193 [allFonts addObject:face]; 194 [fontFamilyTable setObject:family forKey:face]; 195 } 196 } 197 } 198 199 sFilteredFonts = allFonts; 200 sFontFamilyTable = fontFamilyTable; 201 } 202 203 return sFilteredFonts; 204 } 205 206 #pragma mark --- sun.font.CFontManager JNI --- 207 208 static OSStatus CreateFSRef(FSRef *myFSRefPtr, NSString *inPath) 209 { 210 return FSPathMakeRef((UInt8 *)[inPath fileSystemRepresentation], 211 myFSRefPtr, NULL); 212 } 213 214 // /* 215 // * Class: sun_font_CFontManager 216 // * Method: loadFileFont 217 // * Signature: (Ljava/lang/String;)Lsun/font/Font2D; 218 // */ 219 // JNIEXPORT /* sun.font.CFont */ jobject JNICALL 220 // Java_sun_font_CFontManager_loadFileFont 221 // (JNIEnv *env, jclass obj, jstring fontpath) 222 // { 223 // jobject result = NULL; 224 // 225 // JNF_COCOA_ENTER(env); 226 // 227 // NSString *nsFilePath = JNFJavaToNSString(env, fontpath); 228 // jstring javaFontName = NULL; 229 // 230 // // 231 // // Note: This API uses ATS and can therefore return Carbon error codes. 232 // // These codes can be found at: 233 // // http://developer.apple.com/techpubs/macosx/Carbon/Files/FileManager/File_Manager/ResultCodes/ResultCodes.html 234 // // 235 // 236 // FSRef iFile; 237 // OSStatus status = CreateFSRef(&iFile, nsFilePath); 238 // 239 // if (status == noErr) { 240 // ATSFontContainerRef oContainer; 241 // status = ATSFontActivateFromFileReference(&iFile, kATSFontContextLocal, 242 // kATSFontFormatUnspecified, 243 // NULL, 244 // kATSOptionFlagsUseDataFork, 245 // &oContainer); 246 // if (status == noErr) { 247 // ATSFontRef ioArray[1]; 248 // ItemCount oCount; 249 // status = ATSFontFindFromContainer(oContainer, 250 // kATSOptionFlagsUseDataFork, 251 // 1, ioArray, &oCount); 252 // 253 // if (status == noErr) { 254 // CFStringRef oName; 255 // status = ATSFontGetPostScriptName(ioArray[0], 256 // kATSOptionFlagsUseDataFork, 257 // &oName); 258 // if (status == noErr) { 259 // javaFontName = JNFNSToJavaString(env, (NSString *)oName); 260 // CFRelease(oName); 261 // } 262 // } 263 // } 264 // } 265 // 266 // if (javaFontName != NULL) { 267 // // create the CFont! 268 // static JNF_CLASS_CACHE(sjc_CFont, "sun/font/CFont"); 269 // static JNF_CTOR_CACHE(sjf_CFont_ctor, 270 // sjc_CFont, "(Ljava/lang/String;)V"); 271 // result = JNFNewObject(env, sjf_CFont_ctor, javaFontName); 272 // } 273 // 274 // JNF_COCOA_EXIT(env); 275 // 276 // return result; 277 // } 278 279 /* 280 * Class: sun_font_CFontManager 281 * Method: loadNativeFonts 282 * Signature: ()V 283 */ 284 JNIEXPORT void JNICALL 285 Java_sun_font_CFontManager_loadNativeFonts 286 (JNIEnv *env, jobject jthis) 287 { 288 static JNF_CLASS_CACHE(jc_CFontManager, 289 "sun/font/CFontManager"); 290 static JNF_MEMBER_CACHE(jm_registerFont, jc_CFontManager, 291 "registerFont", 292 "(Ljava/lang/String;Ljava/lang/String;)V"); 293 294 jint num = 0; 295 296 JNF_COCOA_ENTER(env); 297 298 NSArray *filteredFonts = GetFilteredFonts(); 299 num = (jint)[filteredFonts count]; 300 301 jint i; 302 for (i = 0; i < num; i++) { 303 NSString *fontname = [filteredFonts objectAtIndex:i]; 304 jobject jFontName = JNFNSToJavaString(env, fontname); 305 jobject jFontFamilyName = 306 JNFNSToJavaString(env, GetFamilyNameForFontName(fontname)); 307 308 JNFCallVoidMethod(env, jthis, 309 jm_registerFont, jFontName, jFontFamilyName); 310 (*env)->DeleteLocalRef(env, jFontName); 311 (*env)->DeleteLocalRef(env, jFontFamilyName); 312 } 313 314 JNF_COCOA_EXIT(env); 315 } 316 317 /* 318 * Class: Java_sun_font_CFontManager_loadNativeDirFonts 319 * Method: loadNativeDirFonts 320 * Signature: (Ljava/lang/String;)V; 321 */ 322 JNIEXPORT void JNICALL 323 Java_sun_font_CFontManager_loadNativeDirFonts 324 (JNIEnv *env, jclass clz, jstring filename) 325 { 326 JNF_COCOA_ENTER(env); 327 328 NSString *nsFilePath = JNFJavaToNSString(env, filename); 329 330 FSRef iFile; 331 OSStatus status = CreateFSRef(&iFile, nsFilePath); 332 333 if (status == noErr) { 334 ATSFontContainerRef oContainer; 335 status = ATSFontActivateFromFileReference(&iFile, kATSFontContextLocal, 336 kATSFontFormatUnspecified, 337 NULL, kNilOptions, 338 &oContainer); 339 } 340 341 JNF_COCOA_EXIT(env); 342 } 343 344 #pragma mark --- sun.font.CFont JNI --- 345 346 /* 347 * Class: sun_font_CFont 348 * Method: initNativeFont 349 * Signature: (Ljava/lang/String;I)J 350 */ 351 JNIEXPORT jlong JNICALL 352 Java_sun_font_CFont_createNativeFont 353 (JNIEnv *env, jclass clazz, 354 jstring nativeFontName, jint style) 355 { 356 AWTFont *awtFont = nil; 357 358 JNF_COCOA_ENTER(env); 359 360 awtFont = 361 [AWTFont awtFontForName:JNFJavaToNSString(env, nativeFontName) 362 style:style]; // autoreleased 363 364 if (awtFont) { 365 CFRetain(awtFont); // GC 366 } 367 368 JNF_COCOA_EXIT(env); 369 370 return ptr_to_jlong(awtFont); 371 } 372 373 /* 374 * Class: sun_font_CFont 375 * Method: getWidthNative 376 * Signature: (J)F 377 */ 378 JNIEXPORT jfloat JNICALL 379 Java_sun_font_CFont_getWidthNative 380 (JNIEnv *env, jobject cfont, jlong awtFontPtr) 381 { 382 float widthVal; 383 JNF_COCOA_ENTER(env); 384 385 AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); 386 NSFont* nsFont = awtFont->fFont; 387 NSFontDescriptor *fontDescriptor = nsFont.fontDescriptor; 388 NSDictionary *fontTraits = [fontDescriptor objectForKey : NSFontTraitsAttribute]; 389 NSNumber *width = [fontTraits objectForKey : NSFontWidthTrait]; 390 widthVal = (float)[width floatValue]; 391 392 JNF_COCOA_EXIT(env); 393 return (jfloat)widthVal; 394 } 395 396 /* 397 * Class: sun_font_CFont 398 * Method: getWeightNative 399 * Signature: (J)F 400 */ 401 JNIEXPORT jfloat JNICALL 402 Java_sun_font_CFont_getWeightNative 403 (JNIEnv *env, jobject cfont, jlong awtFontPtr) 404 { 405 float weightVal; 406 JNF_COCOA_ENTER(env); 407 408 AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); 409 NSFont* nsFont = awtFont->fFont; 410 NSFontDescriptor *fontDescriptor = nsFont.fontDescriptor; 411 NSDictionary *fontTraits = [fontDescriptor objectForKey : NSFontTraitsAttribute]; 412 NSNumber *weight = [fontTraits objectForKey : NSFontWeightTrait]; 413 weightVal = (float)[weight floatValue]; 414 415 JNF_COCOA_EXIT(env); 416 return (jfloat)weightVal; 417 } 418 419 /* 420 * Class: sun_font_CFont 421 * Method: disposeNativeFont 422 * Signature: (J)V 423 */ 424 JNIEXPORT void JNICALL 425 Java_sun_font_CFont_disposeNativeFont 426 (JNIEnv *env, jclass clazz, jlong awtFontPtr) 427 { 428 JNF_COCOA_ENTER(env); 429 430 if (awtFontPtr) { 431 CFRelease((AWTFont *)jlong_to_ptr(awtFontPtr)); // GC 432 } 433 434 JNF_COCOA_EXIT(env); 435 } 436 437 438 #pragma mark --- Miscellaneous JNI --- 439 440 #ifndef HEADLESS 441 /* 442 * Class: sun_awt_PlatformFont 443 * Method: initIDs 444 * Signature: ()V 445 */ 446 JNIEXPORT void JNICALL 447 Java_sun_awt_PlatformFont_initIDs 448 (JNIEnv *env, jclass cls) 449 { 450 } 451 452 /* 453 * Class: sun_awt_FontDescriptor 454 * Method: initIDs 455 * Signature: ()V 456 */ 457 JNIEXPORT void JNICALL 458 Java_sun_awt_FontDescriptor_initIDs 459 (JNIEnv *env, jclass cls) 460 { 461 } 462 #endif