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 39 #define DEBUG 40 41 @implementation AWTFont 42 43 - (id) initWithFont:(NSFont *)font isFakeItalic:(BOOL)isFakeItalic { 44 self = [super init]; 45 if (self) { 46 fIsFakeItalic = isFakeItalic; 47 fFont = [font retain]; 48 fNativeCGFont = CTFontCopyGraphicsFont((CTFontRef)font, NULL); 49 } 50 return self; 51 } 52 53 - (void) dealloc { 54 [fFont release]; 55 fFont = nil; 56 57 if (fNativeCGFont) { 58 CGFontRelease(fNativeCGFont); 59 fNativeCGFont = NULL; 60 } 61 62 [super dealloc]; 63 } 64 65 - (void) finalize { 66 if (fNativeCGFont) { 67 CGFontRelease(fNativeCGFont); 68 fNativeCGFont = NULL; 69 } 70 [super finalize]; 71 } 72 73 + (AWTFont *) awtFontForName:(NSString *)name 74 style:(int)style 75 isFakeItalic:(BOOL)isFakeItalic 76 { 77 // create font with family & size 78 NSFont *nsFont = [NSFont fontWithName:name size:1.0]; 79 80 if (nsFont == nil) { 81 // if can't get font of that name, substitute system default font 82 nsFont = [NSFont fontWithName:@"Lucida Grande" size:1.0]; 83 #ifdef DEBUG 84 NSLog(@"needed to substitute Lucida Grande for: %@", name); 85 #endif 86 } 87 88 // create an italic style (if one is installed) 89 if (style & java_awt_Font_ITALIC) { 90 nsFont = [[NSFontManager sharedFontManager] convertFont:nsFont toHaveTrait:NSItalicFontMask]; 91 } 92 93 // create a bold style (if one is installed) 94 if (style & java_awt_Font_BOLD) { 95 nsFont = [[NSFontManager sharedFontManager] convertFont:nsFont toHaveTrait:NSBoldFontMask]; 96 } 97 98 return [[[AWTFont alloc] initWithFont:nsFont isFakeItalic:isFakeItalic] autorelease]; 99 } 100 101 + (NSFont *) nsFontForJavaFont:(jobject)javaFont env:(JNIEnv *)env { 102 if (javaFont == NULL) { 103 #ifdef DEBUG 104 NSLog(@"nil font"); 105 #endif 106 return nil; 107 } 108 109 static JNF_CLASS_CACHE(jc_Font, "java/awt/Font"); 110 111 // obtain the Font2D 112 static JNF_MEMBER_CACHE(jm_Font_getFont2D, jc_Font, "getFont2D", "()Lsun/font/Font2D;"); 113 jobject font2d = JNFCallObjectMethod(env, javaFont, jm_Font_getFont2D); 114 if (font2d == NULL) { 115 #ifdef DEBUG 116 NSLog(@"nil font2d"); 117 #endif 118 return nil; 119 } 120 121 // if it's not a CFont, it's likely one of TTF or OTF fonts 122 // from the Sun rendering loops 123 static JNF_CLASS_CACHE(jc_CFont, "sun/font/CFont"); 124 if (!JNFIsInstanceOf(env, font2d, &jc_CFont)) { 125 #ifdef DEBUG 126 NSLog(@"font2d !instanceof CFont"); 127 #endif 128 return nil; 129 } 130 131 static JNF_MEMBER_CACHE(jm_CFont_getFontStrike, jc_CFont, "getStrike", "(Ljava/awt/Font;)Lsun/font/FontStrike;"); 132 jobject fontStrike = JNFCallObjectMethod(env, font2d, jm_CFont_getFontStrike, javaFont); 133 134 static JNF_CLASS_CACHE(jc_CStrike, "sun/font/CStrike"); 135 if (!JNFIsInstanceOf(env, fontStrike, &jc_CStrike)) { 136 #ifdef DEBUG 137 NSLog(@"fontStrike !instanceof CStrike"); 138 #endif 139 return nil; 140 } 141 142 static JNF_MEMBER_CACHE(jm_CStrike_nativeStrikePtr, jc_CStrike, "getNativeStrikePtr", "()J"); 143 jlong awtStrikePtr = JNFCallLongMethod(env, fontStrike, jm_CStrike_nativeStrikePtr); 144 if (awtStrikePtr == 0L) { 145 #ifdef DEBUG 146 NSLog(@"nil nativeFontPtr from CFont"); 147 #endif 148 return nil; 149 } 150 151 AWTStrike *strike = (AWTStrike *)jlong_to_ptr(awtStrikePtr); 152 153 return [NSFont fontWithName:[strike->fAWTFont->fFont fontName] matrix:(CGFloat *)(&(strike->fAltTx))]; 154 } 155 156 @end 157 158 159 #pragma mark --- Font Discovery and Loading --- 160 161 static NSArray* sFilteredFonts = nil; 162 static NSDictionary* sFontFamilyTable = nil; 163 164 static NSString* 165 GetFamilyNameForFontName(NSString* fontname) 166 { 167 return [sFontFamilyTable objectForKey:fontname]; 168 } 169 170 static NSArray* 171 GetFilteredFonts() 172 { 173 if (sFilteredFonts == nil) { 174 NSFontManager *fontManager = [NSFontManager sharedFontManager]; 175 NSUInteger fontCount = [[fontManager availableFonts] count]; 176 177 NSMutableArray *allFonts = [[NSMutableArray alloc] initWithCapacity:fontCount]; 178 NSMutableDictionary* fontFamilyTable = [[NSMutableDictionary alloc] initWithCapacity:fontCount]; 179 NSArray *allFamilies = [fontManager availableFontFamilies]; 180 181 NSUInteger familyCount = [allFamilies count]; 182 183 NSUInteger familyIndex; 184 for (familyIndex = 0; familyIndex < familyCount; familyIndex++) { 185 NSString *family = [allFamilies objectAtIndex:familyIndex]; 186 187 if ((family == nil) || [family characterAtIndex:0] == '.') { 188 continue; 189 } 190 191 NSArray *fontFaces = [fontManager availableMembersOfFontFamily:family]; 192 NSUInteger faceCount = [fontFaces count]; 193 194 NSUInteger faceIndex; 195 for (faceIndex = 0; faceIndex < faceCount; faceIndex++) { 196 NSString* face = [[fontFaces objectAtIndex:faceIndex] objectAtIndex:0]; 197 if (face != nil) { 198 [allFonts addObject:face]; 199 [fontFamilyTable setObject:family forKey:face]; 200 } 201 } 202 } 203 204 sFilteredFonts = allFonts; 205 sFontFamilyTable = fontFamilyTable; 206 } 207 208 return sFilteredFonts; 209 } 210 211 #pragma mark --- sun.font.CFontManager JNI --- 212 213 static OSStatus CreateFSRef(FSRef *myFSRefPtr, NSString *inPath) 214 { 215 return FSPathMakeRef((UInt8 *)[inPath fileSystemRepresentation], 216 myFSRefPtr, NULL); 217 } 218 219 // /* 220 // * Class: sun_font_CFontManager 221 // * Method: loadFileFont 222 // * Signature: (Ljava/lang/String;)Lsun/font/Font2D; 223 // */ 224 // JNIEXPORT /* sun.font.CFont */ jobject JNICALL 225 // Java_sun_font_CFontManager_loadFileFont 226 // (JNIEnv *env, jclass obj, jstring fontpath) 227 // { 228 // jobject result = NULL; 229 // 230 // JNF_COCOA_ENTER(env); 231 // 232 // NSString *nsFilePath = JNFJavaToNSString(env, fontpath); 233 // jstring javaFontName = NULL; 234 // 235 // // 236 // // Note: This API uses ATS and can therefore return Carbon error codes. 237 // // These codes can be found at: 238 // // http://developer.apple.com/techpubs/macosx/Carbon/Files/FileManager/File_Manager/ResultCodes/ResultCodes.html 239 // // 240 // 241 // FSRef iFile; 242 // OSStatus status = CreateFSRef(&iFile, nsFilePath); 243 // 244 // if (status == noErr) { 245 // ATSFontContainerRef oContainer; 246 // status = ATSFontActivateFromFileReference(&iFile, kATSFontContextLocal, 247 // kATSFontFormatUnspecified, 248 // NULL, 249 // kATSOptionFlagsUseDataFork, 250 // &oContainer); 251 // if (status == noErr) { 252 // ATSFontRef ioArray[1]; 253 // ItemCount oCount; 254 // status = ATSFontFindFromContainer(oContainer, 255 // kATSOptionFlagsUseDataFork, 256 // 1, ioArray, &oCount); 257 // 258 // if (status == noErr) { 259 // CFStringRef oName; 260 // status = ATSFontGetPostScriptName(ioArray[0], 261 // kATSOptionFlagsUseDataFork, 262 // &oName); 263 // if (status == noErr) { 264 // javaFontName = JNFNSToJavaString(env, (NSString *)oName); 265 // CFRelease(oName); 266 // } 267 // } 268 // } 269 // } 270 // 271 // if (javaFontName != NULL) { 272 // // create the CFont! 273 // static JNF_CLASS_CACHE(sjc_CFont, "sun/font/CFont"); 274 // static JNF_CTOR_CACHE(sjf_CFont_ctor, 275 // sjc_CFont, "(Ljava/lang/String;)V"); 276 // result = JNFNewObject(env, sjf_CFont_ctor, javaFontName); 277 // } 278 // 279 // JNF_COCOA_EXIT(env); 280 // 281 // return result; 282 // } 283 284 /* 285 * Class: sun_font_CFontManager 286 * Method: loadNativeFonts 287 * Signature: ()V 288 */ 289 JNIEXPORT void JNICALL 290 Java_sun_font_CFontManager_loadNativeFonts 291 (JNIEnv *env, jobject jthis) 292 { 293 static JNF_CLASS_CACHE(jc_CFontManager, 294 "sun/font/CFontManager"); 295 static JNF_MEMBER_CACHE(jm_registerFont, jc_CFontManager, 296 "registerFont", 297 "(Ljava/lang/String;Ljava/lang/String;)V"); 298 299 jint num = 0; 300 301 JNF_COCOA_ENTER(env); 302 303 NSArray *filteredFonts = GetFilteredFonts(); 304 num = (jint)[filteredFonts count]; 305 306 jint i; 307 for (i = 0; i < num; i++) { 308 NSString *fontname = [filteredFonts objectAtIndex:i]; 309 jobject jFontName = JNFNSToJavaString(env, fontname); 310 jobject jFontFamilyName = 311 JNFNSToJavaString(env, GetFamilyNameForFontName(fontname)); 312 313 JNFCallVoidMethod(env, jthis, 314 jm_registerFont, jFontName, jFontFamilyName); 315 } 316 317 JNF_COCOA_EXIT(env); 318 } 319 320 /* 321 * Class: Java_sun_font_CFontManager_loadNativeDirFonts 322 * Method: loadNativeDirFonts 323 * Signature: (Ljava/lang/String;)V; 324 */ 325 JNIEXPORT void JNICALL 326 Java_sun_font_CFontManager_loadNativeDirFonts 327 (JNIEnv *env, jclass clz, jstring filename) 328 { 329 JNF_COCOA_ENTER(env); 330 331 NSString *nsFilePath = JNFJavaToNSString(env, filename); 332 333 FSRef iFile; 334 OSStatus status = CreateFSRef(&iFile, nsFilePath); 335 336 if (status == noErr) { 337 ATSFontContainerRef oContainer; 338 status = ATSFontActivateFromFileReference(&iFile, kATSFontContextLocal, 339 kATSFontFormatUnspecified, 340 NULL, kNilOptions, 341 &oContainer); 342 } 343 344 JNF_COCOA_EXIT(env); 345 } 346 347 #pragma mark --- sun.font.CFont JNI --- 348 349 /* 350 * Class: sun_font_CFont 351 * Method: initNativeFont 352 * Signature: (Ljava/lang/String;I)J 353 */ 354 JNIEXPORT jlong JNICALL 355 Java_sun_font_CFont_createNativeFont 356 (JNIEnv *env, jclass clazz, 357 jstring nativeFontName, jint style, jboolean isFakeItalic) 358 { 359 AWTFont *awtFont = nil; 360 361 JNF_COCOA_ENTER(env); 362 363 awtFont = 364 [AWTFont awtFontForName:JNFJavaToNSString(env, nativeFontName) 365 style:style 366 isFakeItalic:isFakeItalic]; // autoreleased 367 368 if (awtFont) { 369 CFRetain(awtFont); // GC 370 } 371 372 JNF_COCOA_EXIT(env); 373 374 return ptr_to_jlong(awtFont); 375 } 376 377 /* 378 * Class: sun_font_CFont 379 * Method: disposeNativeFont 380 * Signature: (J)V 381 */ 382 JNIEXPORT void JNICALL 383 Java_sun_font_CFont_disposeNativeFont 384 (JNIEnv *env, jclass clazz, jlong awtFontPtr) 385 { 386 JNF_COCOA_ENTER(env); 387 388 if (awtFontPtr) { 389 CFRelease((AWTFont *)jlong_to_ptr(awtFontPtr)); // GC 390 } 391 392 JNF_COCOA_EXIT(env); 393 } 394 395 396 #pragma mark --- Miscellaneous JNI --- 397 398 #ifndef HEADLESS 399 /* 400 * Class: sun_awt_PlatformFont 401 * Method: initIDs 402 * Signature: ()V 403 */ 404 JNIEXPORT void JNICALL 405 Java_sun_awt_PlatformFont_initIDs 406 (JNIEnv *env, jclass cls) 407 { 408 } 409 410 /* 411 * Class: sun_awt_FontDescriptor 412 * Method: initIDs 413 * Signature: ()V 414 */ 415 JNIEXPORT void JNICALL 416 Java_sun_awt_FontDescriptor_initIDs 417 (JNIEnv *env, jclass cls) 418 { 419 } 420 #endif