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