| 1 | /***************************************************************************/ | 
|---|
| 2 | /*                                                                         */ | 
|---|
| 3 | /*  ftmac.c                                                                */ | 
|---|
| 4 | /*                                                                         */ | 
|---|
| 5 | /*    Mac FOND support.  Written by just@letterror.com.                    */ | 
|---|
| 6 | /*  Heavily modified by mpsuzuki, George Williams, and Sean McBride.       */ | 
|---|
| 7 | /*                                                                         */ | 
|---|
| 8 | /*  This file is for Mac OS X only; see builds/mac/ftoldmac.c for          */ | 
|---|
| 9 | /*  classic platforms built by MPW.                                        */ | 
|---|
| 10 | /*                                                                         */ | 
|---|
| 11 | /*  Copyright 1996-2018 by                                                 */ | 
|---|
| 12 | /*  Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.     */ | 
|---|
| 13 | /*                                                                         */ | 
|---|
| 14 | /*  This file is part of the FreeType project, and may only be used,       */ | 
|---|
| 15 | /*  modified, and distributed under the terms of the FreeType project      */ | 
|---|
| 16 | /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */ | 
|---|
| 17 | /*  this file you indicate that you have read the license and              */ | 
|---|
| 18 | /*  understand and accept it fully.                                        */ | 
|---|
| 19 | /*                                                                         */ | 
|---|
| 20 | /***************************************************************************/ | 
|---|
| 21 |  | 
|---|
| 22 |  | 
|---|
| 23 | /* | 
|---|
| 24 | Notes | 
|---|
| 25 |  | 
|---|
| 26 | Mac suitcase files can (and often do!) contain multiple fonts.  To | 
|---|
| 27 | support this I use the face_index argument of FT_(Open|New)_Face() | 
|---|
| 28 | functions, and pretend the suitcase file is a collection. | 
|---|
| 29 |  | 
|---|
| 30 | Warning: fbit and NFNT bitmap resources are not supported yet.  In old | 
|---|
| 31 | sfnt fonts, bitmap glyph data for each size is stored in each `NFNT' | 
|---|
| 32 | resources instead of the `bdat' table in the sfnt resource.  Therefore, | 
|---|
| 33 | face->num_fixed_sizes is set to 0, because bitmap data in `NFNT' | 
|---|
| 34 | resource is unavailable at present. | 
|---|
| 35 |  | 
|---|
| 36 | The Mac FOND support works roughly like this: | 
|---|
| 37 |  | 
|---|
| 38 | - Check whether the offered stream points to a Mac suitcase file.  This | 
|---|
| 39 | is done by checking the file type: it has to be 'FFIL' or 'tfil'.  The | 
|---|
| 40 | stream that gets passed to our init_face() routine is a stdio stream, | 
|---|
| 41 | which isn't usable for us, since the FOND resources live in the | 
|---|
| 42 | resource fork.  So we just grab the stream->pathname field. | 
|---|
| 43 |  | 
|---|
| 44 | - Read the FOND resource into memory, then check whether there is a | 
|---|
| 45 | TrueType font and/or(!) a Type 1 font available. | 
|---|
| 46 |  | 
|---|
| 47 | - If there is a Type 1 font available (as a separate `LWFN' file), read | 
|---|
| 48 | its data into memory, massage it slightly so it becomes PFB data, wrap | 
|---|
| 49 | it into a memory stream, load the Type 1 driver and delegate the rest | 
|---|
| 50 | of the work to it by calling FT_Open_Face().  (XXX TODO: after this | 
|---|
| 51 | has been done, the kerning data from the FOND resource should be | 
|---|
| 52 | appended to the face: On the Mac there are usually no AFM files | 
|---|
| 53 | available.  However, this is tricky since we need to map Mac char | 
|---|
| 54 | codes to ps glyph names to glyph ID's...) | 
|---|
| 55 |  | 
|---|
| 56 | - If there is a TrueType font (an `sfnt' resource), read it into memory, | 
|---|
| 57 | wrap it into a memory stream, load the TrueType driver and delegate | 
|---|
| 58 | the rest of the work to it, by calling FT_Open_Face(). | 
|---|
| 59 |  | 
|---|
| 60 | - Some suitcase fonts (notably Onyx) might point the `LWFN' file to | 
|---|
| 61 | itself, even though it doesn't contains `POST' resources.  To handle | 
|---|
| 62 | this special case without opening the file an extra time, we just | 
|---|
| 63 | ignore errors from the `LWFN' and fallback to the `sfnt' if both are | 
|---|
| 64 | available. | 
|---|
| 65 | */ | 
|---|
| 66 |  | 
|---|
| 67 |  | 
|---|
| 68 | #include <ft2build.h> | 
|---|
| 69 | #include FT_FREETYPE_H | 
|---|
| 70 | #include FT_TRUETYPE_TAGS_H | 
|---|
| 71 | #include FT_INTERNAL_STREAM_H | 
|---|
| 72 | #include "ftbase.h" | 
|---|
| 73 |  | 
|---|
| 74 |  | 
|---|
| 75 | #ifdef FT_MACINTOSH | 
|---|
| 76 |  | 
|---|
| 77 | /* This is for Mac OS X.  Without redefinition, OS_INLINE */ | 
|---|
| 78 | /* expands to `static inline' which doesn't survive the   */ | 
|---|
| 79 | /* -ansi compilation flag of GCC.                         */ | 
|---|
| 80 | #if !HAVE_ANSI_OS_INLINE | 
|---|
| 81 | #undef  OS_INLINE | 
|---|
| 82 | #define OS_INLINE  static __inline__ | 
|---|
| 83 | #endif | 
|---|
| 84 |  | 
|---|
| 85 | /* `configure' checks the availability of `ResourceIndex' strictly */ | 
|---|
| 86 | /* and sets HAVE_TYPE_RESOURCE_INDEX 1 or 0 always.  If it is      */ | 
|---|
| 87 | /* not set (e.g., a build without `configure'), the availability   */ | 
|---|
| 88 | /* is guessed from the SDK version.                                */ | 
|---|
| 89 | #ifndef HAVE_TYPE_RESOURCE_INDEX | 
|---|
| 90 | #if !defined( MAC_OS_X_VERSION_10_5 ) || \ | 
|---|
| 91 | ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 ) | 
|---|
| 92 | #define HAVE_TYPE_RESOURCE_INDEX 0 | 
|---|
| 93 | #else | 
|---|
| 94 | #define HAVE_TYPE_RESOURCE_INDEX 1 | 
|---|
| 95 | #endif | 
|---|
| 96 | #endif /* !HAVE_TYPE_RESOURCE_INDEX */ | 
|---|
| 97 |  | 
|---|
| 98 | #if ( HAVE_TYPE_RESOURCE_INDEX == 0 ) | 
|---|
| 99 | typedef short  ResourceIndex; | 
|---|
| 100 | #endif | 
|---|
| 101 |  | 
|---|
| 102 | #include <CoreServices/CoreServices.h> | 
|---|
| 103 | #include <ApplicationServices/ApplicationServices.h> | 
|---|
| 104 | #include <sys/syslimits.h> /* PATH_MAX */ | 
|---|
| 105 |  | 
|---|
| 106 | /* Don't want warnings about our own use of deprecated functions. */ | 
|---|
| 107 | #define FT_DEPRECATED_ATTRIBUTE | 
|---|
| 108 |  | 
|---|
| 109 | #include FT_MAC_H | 
|---|
| 110 |  | 
|---|
| 111 | #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */ | 
|---|
| 112 | #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault | 
|---|
| 113 | #endif | 
|---|
| 114 |  | 
|---|
| 115 |  | 
|---|
| 116 | /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over | 
|---|
| 117 | TrueType in case *both* are available (this is not common, | 
|---|
| 118 | but it *is* possible). */ | 
|---|
| 119 | #ifndef PREFER_LWFN | 
|---|
| 120 | #define PREFER_LWFN  1 | 
|---|
| 121 | #endif | 
|---|
| 122 |  | 
|---|
| 123 |  | 
|---|
| 124 | /* This function is deprecated because FSSpec is deprecated in Mac OS X  */ | 
|---|
| 125 | FT_EXPORT_DEF( FT_Error ) | 
|---|
| 126 | FT_GetFile_From_Mac_Name( const char*  fontName, | 
|---|
| 127 | FSSpec*      pathSpec, | 
|---|
| 128 | FT_Long*     face_index ) | 
|---|
| 129 | { | 
|---|
| 130 | FT_UNUSED( fontName ); | 
|---|
| 131 | FT_UNUSED( pathSpec ); | 
|---|
| 132 | FT_UNUSED( face_index ); | 
|---|
| 133 |  | 
|---|
| 134 | return FT_THROW( Unimplemented_Feature ); | 
|---|
| 135 | } | 
|---|
| 136 |  | 
|---|
| 137 |  | 
|---|
| 138 | /* Private function.                                         */ | 
|---|
| 139 | /* The FSSpec type has been discouraged for a long time,     */ | 
|---|
| 140 | /* unfortunately an FSRef replacement API for                */ | 
|---|
| 141 | /* ATSFontGetFileSpecification() is only available in        */ | 
|---|
| 142 | /* Mac OS X 10.5 and later.                                  */ | 
|---|
| 143 | static OSStatus | 
|---|
| 144 | FT_ATSFontGetFileReference( ATSFontRef  ats_font_id, | 
|---|
| 145 | FSRef*      ats_font_ref ) | 
|---|
| 146 | { | 
|---|
| 147 | #if defined( MAC_OS_X_VERSION_10_5 ) && \ | 
|---|
| 148 | ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) | 
|---|
| 149 |  | 
|---|
| 150 | OSStatus  err; | 
|---|
| 151 |  | 
|---|
| 152 | err = ATSFontGetFileReference( ats_font_id, ats_font_ref ); | 
|---|
| 153 |  | 
|---|
| 154 | return err; | 
|---|
| 155 | #elif __LP64__ /* No 64bit Carbon API on legacy platforms */ | 
|---|
| 156 | FT_UNUSED( ats_font_id ); | 
|---|
| 157 | FT_UNUSED( ats_font_ref ); | 
|---|
| 158 |  | 
|---|
| 159 |  | 
|---|
| 160 | return fnfErr; | 
|---|
| 161 | #else /* 32bit Carbon API on legacy platforms */ | 
|---|
| 162 | OSStatus  err; | 
|---|
| 163 | FSSpec    spec; | 
|---|
| 164 |  | 
|---|
| 165 |  | 
|---|
| 166 | err = ATSFontGetFileSpecification( ats_font_id, &spec ); | 
|---|
| 167 | if ( noErr == err ) | 
|---|
| 168 | err = FSpMakeFSRef( &spec, ats_font_ref ); | 
|---|
| 169 |  | 
|---|
| 170 | return err; | 
|---|
| 171 | #endif | 
|---|
| 172 | } | 
|---|
| 173 |  | 
|---|
| 174 |  | 
|---|
| 175 | static FT_Error | 
|---|
| 176 | FT_GetFileRef_From_Mac_ATS_Name( const char*  fontName, | 
|---|
| 177 | FSRef*       ats_font_ref, | 
|---|
| 178 | FT_Long*     face_index ) | 
|---|
| 179 | { | 
|---|
| 180 | CFStringRef  cf_fontName; | 
|---|
| 181 | ATSFontRef   ats_font_id; | 
|---|
| 182 |  | 
|---|
| 183 |  | 
|---|
| 184 | *face_index = 0; | 
|---|
| 185 |  | 
|---|
| 186 | cf_fontName = CFStringCreateWithCString( NULL, fontName, | 
|---|
| 187 | kCFStringEncodingMacRoman ); | 
|---|
| 188 | ats_font_id = ATSFontFindFromName( cf_fontName, | 
|---|
| 189 | kATSOptionFlagsUnRestrictedScope ); | 
|---|
| 190 | CFRelease( cf_fontName ); | 
|---|
| 191 |  | 
|---|
| 192 | if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL ) | 
|---|
| 193 | return FT_THROW( Unknown_File_Format ); | 
|---|
| 194 |  | 
|---|
| 195 | if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) ) | 
|---|
| 196 | return FT_THROW( Unknown_File_Format ); | 
|---|
| 197 |  | 
|---|
| 198 | /* face_index calculation by searching preceding fontIDs */ | 
|---|
| 199 | /* with same FSRef                                       */ | 
|---|
| 200 | { | 
|---|
| 201 | ATSFontRef  id2 = ats_font_id - 1; | 
|---|
| 202 | FSRef       ref2; | 
|---|
| 203 |  | 
|---|
| 204 |  | 
|---|
| 205 | while ( id2 > 0 ) | 
|---|
| 206 | { | 
|---|
| 207 | if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) ) | 
|---|
| 208 | break; | 
|---|
| 209 | if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) ) | 
|---|
| 210 | break; | 
|---|
| 211 |  | 
|---|
| 212 | id2 --; | 
|---|
| 213 | } | 
|---|
| 214 | *face_index = ats_font_id - ( id2 + 1 ); | 
|---|
| 215 | } | 
|---|
| 216 |  | 
|---|
| 217 | return FT_Err_Ok; | 
|---|
| 218 | } | 
|---|
| 219 |  | 
|---|
| 220 |  | 
|---|
| 221 | FT_EXPORT_DEF( FT_Error ) | 
|---|
| 222 | FT_GetFilePath_From_Mac_ATS_Name( const char*  fontName, | 
|---|
| 223 | UInt8*       path, | 
|---|
| 224 | UInt32       maxPathSize, | 
|---|
| 225 | FT_Long*     face_index ) | 
|---|
| 226 | { | 
|---|
| 227 | FSRef     ref; | 
|---|
| 228 | FT_Error  err; | 
|---|
| 229 |  | 
|---|
| 230 |  | 
|---|
| 231 | if ( !fontName || !face_index ) | 
|---|
| 232 | return FT_THROW( Invalid_Argument); | 
|---|
| 233 |  | 
|---|
| 234 | err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); | 
|---|
| 235 | if ( err ) | 
|---|
| 236 | return err; | 
|---|
| 237 |  | 
|---|
| 238 | if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) ) | 
|---|
| 239 | return FT_THROW( Unknown_File_Format ); | 
|---|
| 240 |  | 
|---|
| 241 | return FT_Err_Ok; | 
|---|
| 242 | } | 
|---|
| 243 |  | 
|---|
| 244 |  | 
|---|
| 245 | /* This function is deprecated because FSSpec is deprecated in Mac OS X  */ | 
|---|
| 246 | FT_EXPORT_DEF( FT_Error ) | 
|---|
| 247 | FT_GetFile_From_Mac_ATS_Name( const char*  fontName, | 
|---|
| 248 | FSSpec*      pathSpec, | 
|---|
| 249 | FT_Long*     face_index ) | 
|---|
| 250 | { | 
|---|
| 251 | #if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \ | 
|---|
| 252 | ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) ) | 
|---|
| 253 | FT_UNUSED( fontName ); | 
|---|
| 254 | FT_UNUSED( pathSpec ); | 
|---|
| 255 | FT_UNUSED( face_index ); | 
|---|
| 256 |  | 
|---|
| 257 | return FT_THROW( Unimplemented_Feature ); | 
|---|
| 258 | #else | 
|---|
| 259 | FSRef     ref; | 
|---|
| 260 | FT_Error  err; | 
|---|
| 261 |  | 
|---|
| 262 |  | 
|---|
| 263 | if ( !fontName || !face_index ) | 
|---|
| 264 | return FT_THROW( Invalid_Argument ); | 
|---|
| 265 |  | 
|---|
| 266 | err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); | 
|---|
| 267 | if ( err ) | 
|---|
| 268 | return err; | 
|---|
| 269 |  | 
|---|
| 270 | if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, | 
|---|
| 271 | pathSpec, NULL ) ) | 
|---|
| 272 | return FT_THROW( Unknown_File_Format ); | 
|---|
| 273 |  | 
|---|
| 274 | return FT_Err_Ok; | 
|---|
| 275 | #endif | 
|---|
| 276 | } | 
|---|
| 277 |  | 
|---|
| 278 |  | 
|---|
| 279 | static OSErr | 
|---|
| 280 | FT_FSPathMakeRes( const UInt8*    pathname, | 
|---|
| 281 | ResFileRefNum*  res ) | 
|---|
| 282 | { | 
|---|
| 283 | OSErr  err; | 
|---|
| 284 | FSRef  ref; | 
|---|
| 285 |  | 
|---|
| 286 |  | 
|---|
| 287 | if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) | 
|---|
| 288 | return FT_THROW( Cannot_Open_Resource ); | 
|---|
| 289 |  | 
|---|
| 290 | /* at present, no support for dfont format */ | 
|---|
| 291 | err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res ); | 
|---|
| 292 | if ( noErr == err ) | 
|---|
| 293 | return err; | 
|---|
| 294 |  | 
|---|
| 295 | /* fallback to original resource-fork font */ | 
|---|
| 296 | *res = FSOpenResFile( &ref, fsRdPerm ); | 
|---|
| 297 | err  = ResError(); | 
|---|
| 298 |  | 
|---|
| 299 | return err; | 
|---|
| 300 | } | 
|---|
| 301 |  | 
|---|
| 302 |  | 
|---|
| 303 | /* Return the file type for given pathname */ | 
|---|
| 304 | static OSType | 
|---|
| 305 | get_file_type_from_path( const UInt8*  pathname ) | 
|---|
| 306 | { | 
|---|
| 307 | FSRef          ref; | 
|---|
| 308 | FSCatalogInfo  info; | 
|---|
| 309 |  | 
|---|
| 310 |  | 
|---|
| 311 | if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) | 
|---|
| 312 | return ( OSType ) 0; | 
|---|
| 313 |  | 
|---|
| 314 | if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info, | 
|---|
| 315 | NULL, NULL, NULL ) ) | 
|---|
| 316 | return ( OSType ) 0; | 
|---|
| 317 |  | 
|---|
| 318 | return ((FInfo *)(info.finderInfo))->fdType; | 
|---|
| 319 | } | 
|---|
| 320 |  | 
|---|
| 321 |  | 
|---|
| 322 | /* Given a PostScript font name, create the Macintosh LWFN file name. */ | 
|---|
| 323 | static void | 
|---|
| 324 | create_lwfn_name( char*   ps_name, | 
|---|
| 325 | Str255  lwfn_file_name ) | 
|---|
| 326 | { | 
|---|
| 327 | int       max = 5, count = 0; | 
|---|
| 328 | FT_Byte*  p = lwfn_file_name; | 
|---|
| 329 | FT_Byte*  q = (FT_Byte*)ps_name; | 
|---|
| 330 |  | 
|---|
| 331 |  | 
|---|
| 332 | lwfn_file_name[0] = 0; | 
|---|
| 333 |  | 
|---|
| 334 | while ( *q ) | 
|---|
| 335 | { | 
|---|
| 336 | if ( ft_isupper( *q ) ) | 
|---|
| 337 | { | 
|---|
| 338 | if ( count ) | 
|---|
| 339 | max = 3; | 
|---|
| 340 | count = 0; | 
|---|
| 341 | } | 
|---|
| 342 | if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) ) | 
|---|
| 343 | { | 
|---|
| 344 | *++p = *q; | 
|---|
| 345 | lwfn_file_name[0]++; | 
|---|
| 346 | count++; | 
|---|
| 347 | } | 
|---|
| 348 | q++; | 
|---|
| 349 | } | 
|---|
| 350 | } | 
|---|
| 351 |  | 
|---|
| 352 |  | 
|---|
| 353 | static short | 
|---|
| 354 | count_faces_sfnt( char*  fond_data ) | 
|---|
| 355 | { | 
|---|
| 356 | /* The count is 1 greater than the value in the FOND.  */ | 
|---|
| 357 | /* Isn't that cute? :-)                                */ | 
|---|
| 358 |  | 
|---|
| 359 | return EndianS16_BtoN( *( (short*)( fond_data + | 
|---|
| 360 | sizeof ( FamRec ) ) ) ) + 1; | 
|---|
| 361 | } | 
|---|
| 362 |  | 
|---|
| 363 |  | 
|---|
| 364 | static short | 
|---|
| 365 | count_faces_scalable( char*  fond_data ) | 
|---|
| 366 | { | 
|---|
| 367 | AsscEntry*  assoc; | 
|---|
| 368 | short       i, face, face_all; | 
|---|
| 369 |  | 
|---|
| 370 |  | 
|---|
| 371 | face_all = EndianS16_BtoN( *( (short *)( fond_data + | 
|---|
| 372 | sizeof ( FamRec ) ) ) ) + 1; | 
|---|
| 373 | assoc    = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); | 
|---|
| 374 | face     = 0; | 
|---|
| 375 |  | 
|---|
| 376 | for ( i = 0; i < face_all; i++ ) | 
|---|
| 377 | { | 
|---|
| 378 | if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) ) | 
|---|
| 379 | face++; | 
|---|
| 380 | } | 
|---|
| 381 | return face; | 
|---|
| 382 | } | 
|---|
| 383 |  | 
|---|
| 384 |  | 
|---|
| 385 | /* Look inside the FOND data, answer whether there should be an SFNT | 
|---|
| 386 | resource, and answer the name of a possible LWFN Type 1 file. | 
|---|
| 387 |  | 
|---|
| 388 | Thanks to Paul Miller (paulm@profoundeffects.com) for the fix | 
|---|
| 389 | to load a face OTHER than the first one in the FOND! | 
|---|
| 390 | */ | 
|---|
| 391 |  | 
|---|
| 392 |  | 
|---|
| 393 | static void | 
|---|
| 394 | parse_fond( char*   fond_data, | 
|---|
| 395 | short*  have_sfnt, | 
|---|
| 396 | ResID*  sfnt_id, | 
|---|
| 397 | Str255  lwfn_file_name, | 
|---|
| 398 | short   face_index ) | 
|---|
| 399 | { | 
|---|
| 400 | AsscEntry*  assoc; | 
|---|
| 401 | AsscEntry*  base_assoc; | 
|---|
| 402 | FamRec*     fond; | 
|---|
| 403 |  | 
|---|
| 404 |  | 
|---|
| 405 | *sfnt_id          = 0; | 
|---|
| 406 | *have_sfnt        = 0; | 
|---|
| 407 | lwfn_file_name[0] = 0; | 
|---|
| 408 |  | 
|---|
| 409 | fond       = (FamRec*)fond_data; | 
|---|
| 410 | assoc      = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); | 
|---|
| 411 | base_assoc = assoc; | 
|---|
| 412 |  | 
|---|
| 413 | /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */ | 
|---|
| 414 | if ( 47 < face_index ) | 
|---|
| 415 | return; | 
|---|
| 416 |  | 
|---|
| 417 | /* Let's do a little range checking before we get too excited here */ | 
|---|
| 418 | if ( face_index < count_faces_sfnt( fond_data ) ) | 
|---|
| 419 | { | 
|---|
| 420 | assoc += face_index;        /* add on the face_index! */ | 
|---|
| 421 |  | 
|---|
| 422 | /* if the face at this index is not scalable, | 
|---|
| 423 | fall back to the first one (old behavior) */ | 
|---|
| 424 | if ( EndianS16_BtoN( assoc->fontSize ) == 0 ) | 
|---|
| 425 | { | 
|---|
| 426 | *have_sfnt = 1; | 
|---|
| 427 | *sfnt_id   = EndianS16_BtoN( assoc->fontID ); | 
|---|
| 428 | } | 
|---|
| 429 | else if ( base_assoc->fontSize == 0 ) | 
|---|
| 430 | { | 
|---|
| 431 | *have_sfnt = 1; | 
|---|
| 432 | *sfnt_id   = EndianS16_BtoN( base_assoc->fontID ); | 
|---|
| 433 | } | 
|---|
| 434 | } | 
|---|
| 435 |  | 
|---|
| 436 | if ( EndianS32_BtoN( fond->ffStylOff ) ) | 
|---|
| 437 | { | 
|---|
| 438 | unsigned char*  p = (unsigned char*)fond_data; | 
|---|
| 439 | StyleTable*     style; | 
|---|
| 440 | unsigned short  string_count; | 
|---|
| 441 | char            ps_name[256]; | 
|---|
| 442 | unsigned char*  names[64]; | 
|---|
| 443 | int             i; | 
|---|
| 444 |  | 
|---|
| 445 |  | 
|---|
| 446 | p += EndianS32_BtoN( fond->ffStylOff ); | 
|---|
| 447 | style = (StyleTable*)p; | 
|---|
| 448 | p += sizeof ( StyleTable ); | 
|---|
| 449 | string_count = EndianS16_BtoN( *(short*)(p) ); | 
|---|
| 450 | string_count = FT_MIN( 64, string_count ); | 
|---|
| 451 | p += sizeof ( short ); | 
|---|
| 452 |  | 
|---|
| 453 | for ( i = 0; i < string_count; i++ ) | 
|---|
| 454 | { | 
|---|
| 455 | names[i] = p; | 
|---|
| 456 | p       += names[i][0]; | 
|---|
| 457 | p++; | 
|---|
| 458 | } | 
|---|
| 459 |  | 
|---|
| 460 | { | 
|---|
| 461 | size_t  ps_name_len = (size_t)names[0][0]; | 
|---|
| 462 |  | 
|---|
| 463 |  | 
|---|
| 464 | if ( ps_name_len != 0 ) | 
|---|
| 465 | { | 
|---|
| 466 | ft_memcpy(ps_name, names[0] + 1, ps_name_len); | 
|---|
| 467 | ps_name[ps_name_len] = 0; | 
|---|
| 468 | } | 
|---|
| 469 | if ( style->indexes[face_index] > 1 && | 
|---|
| 470 | style->indexes[face_index] <= string_count ) | 
|---|
| 471 | { | 
|---|
| 472 | unsigned char*  suffixes = names[style->indexes[face_index] - 1]; | 
|---|
| 473 |  | 
|---|
| 474 |  | 
|---|
| 475 | for ( i = 1; i <= suffixes[0]; i++ ) | 
|---|
| 476 | { | 
|---|
| 477 | unsigned char*  s; | 
|---|
| 478 | size_t          j = suffixes[i] - 1; | 
|---|
| 479 |  | 
|---|
| 480 |  | 
|---|
| 481 | if ( j < string_count && ( s = names[j] ) != NULL ) | 
|---|
| 482 | { | 
|---|
| 483 | size_t  s_len = (size_t)s[0]; | 
|---|
| 484 |  | 
|---|
| 485 |  | 
|---|
| 486 | if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) ) | 
|---|
| 487 | { | 
|---|
| 488 | ft_memcpy( ps_name + ps_name_len, s + 1, s_len ); | 
|---|
| 489 | ps_name_len += s_len; | 
|---|
| 490 | ps_name[ps_name_len] = 0; | 
|---|
| 491 | } | 
|---|
| 492 | } | 
|---|
| 493 | } | 
|---|
| 494 | } | 
|---|
| 495 | } | 
|---|
| 496 |  | 
|---|
| 497 | create_lwfn_name( ps_name, lwfn_file_name ); | 
|---|
| 498 | } | 
|---|
| 499 | } | 
|---|
| 500 |  | 
|---|
| 501 |  | 
|---|
| 502 | static  FT_Error | 
|---|
| 503 | lookup_lwfn_by_fond( const UInt8*      path_fond, | 
|---|
| 504 | ConstStr255Param  base_lwfn, | 
|---|
| 505 | UInt8*            path_lwfn, | 
|---|
| 506 | size_t            path_size ) | 
|---|
| 507 | { | 
|---|
| 508 | FSRef   ref, par_ref; | 
|---|
| 509 | size_t  dirname_len; | 
|---|
| 510 |  | 
|---|
| 511 |  | 
|---|
| 512 | /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */ | 
|---|
| 513 | /* We should not extract parent directory by string manipulation.      */ | 
|---|
| 514 |  | 
|---|
| 515 | if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) ) | 
|---|
| 516 | return FT_THROW( Invalid_Argument ); | 
|---|
| 517 |  | 
|---|
| 518 | if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, | 
|---|
| 519 | NULL, NULL, NULL, &par_ref ) ) | 
|---|
| 520 | return FT_THROW( Invalid_Argument ); | 
|---|
| 521 |  | 
|---|
| 522 | if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) ) | 
|---|
| 523 | return FT_THROW( Invalid_Argument ); | 
|---|
| 524 |  | 
|---|
| 525 | if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size ) | 
|---|
| 526 | return FT_THROW( Invalid_Argument ); | 
|---|
| 527 |  | 
|---|
| 528 | /* now we have absolute dirname in path_lwfn */ | 
|---|
| 529 | ft_strcat( (char *)path_lwfn, "/"); | 
|---|
| 530 | dirname_len = ft_strlen( (char *)path_lwfn ); | 
|---|
| 531 | ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 ); | 
|---|
| 532 | path_lwfn[dirname_len + base_lwfn[0]] = '\0'; | 
|---|
| 533 |  | 
|---|
| 534 | if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) ) | 
|---|
| 535 | return FT_THROW( Cannot_Open_Resource ); | 
|---|
| 536 |  | 
|---|
| 537 | if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, | 
|---|
| 538 | NULL, NULL, NULL, NULL ) ) | 
|---|
| 539 | return FT_THROW( Cannot_Open_Resource ); | 
|---|
| 540 |  | 
|---|
| 541 | return FT_Err_Ok; | 
|---|
| 542 | } | 
|---|
| 543 |  | 
|---|
| 544 |  | 
|---|
| 545 | static short | 
|---|
| 546 | count_faces( Handle        fond, | 
|---|
| 547 | const UInt8*  pathname ) | 
|---|
| 548 | { | 
|---|
| 549 | ResID     sfnt_id; | 
|---|
| 550 | short     have_sfnt, have_lwfn; | 
|---|
| 551 | Str255    lwfn_file_name; | 
|---|
| 552 | UInt8     buff[PATH_MAX]; | 
|---|
| 553 | FT_Error  err; | 
|---|
| 554 | short     num_faces; | 
|---|
| 555 |  | 
|---|
| 556 |  | 
|---|
| 557 | have_sfnt = have_lwfn = 0; | 
|---|
| 558 |  | 
|---|
| 559 | parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 ); | 
|---|
| 560 |  | 
|---|
| 561 | if ( lwfn_file_name[0] ) | 
|---|
| 562 | { | 
|---|
| 563 | err = lookup_lwfn_by_fond( pathname, lwfn_file_name, | 
|---|
| 564 | buff, sizeof ( buff )  ); | 
|---|
| 565 | if ( !err ) | 
|---|
| 566 | have_lwfn = 1; | 
|---|
| 567 | } | 
|---|
| 568 |  | 
|---|
| 569 | if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) | 
|---|
| 570 | num_faces = 1; | 
|---|
| 571 | else | 
|---|
| 572 | num_faces = count_faces_scalable( *fond ); | 
|---|
| 573 |  | 
|---|
| 574 | return num_faces; | 
|---|
| 575 | } | 
|---|
| 576 |  | 
|---|
| 577 |  | 
|---|
| 578 | /* Read Type 1 data from the POST resources inside the LWFN file, | 
|---|
| 579 | return a PFB buffer.  This is somewhat convoluted because the FT2 | 
|---|
| 580 | PFB parser wants the ASCII header as one chunk, and the LWFN | 
|---|
| 581 | chunks are often not organized that way, so we glue chunks | 
|---|
| 582 | of the same type together. */ | 
|---|
| 583 | static FT_Error | 
|---|
| 584 | read_lwfn( FT_Memory      memory, | 
|---|
| 585 | ResFileRefNum  res, | 
|---|
| 586 | FT_Byte**      pfb_data, | 
|---|
| 587 | FT_ULong*      size ) | 
|---|
| 588 | { | 
|---|
| 589 | FT_Error       error = FT_Err_Ok; | 
|---|
| 590 | ResID          res_id; | 
|---|
| 591 | unsigned char  *buffer, *p, *size_p = NULL; | 
|---|
| 592 | FT_ULong       total_size = 0; | 
|---|
| 593 | FT_ULong       old_total_size = 0; | 
|---|
| 594 | FT_ULong       post_size, pfb_chunk_size; | 
|---|
| 595 | Handle         post_data; | 
|---|
| 596 | char           code, last_code; | 
|---|
| 597 |  | 
|---|
| 598 |  | 
|---|
| 599 | UseResFile( res ); | 
|---|
| 600 |  | 
|---|
| 601 | /* First pass: load all POST resources, and determine the size of */ | 
|---|
| 602 | /* the output buffer.                                             */ | 
|---|
| 603 | res_id    = 501; | 
|---|
| 604 | last_code = -1; | 
|---|
| 605 |  | 
|---|
| 606 | for (;;) | 
|---|
| 607 | { | 
|---|
| 608 | post_data = Get1Resource( TTAG_POST, res_id++ ); | 
|---|
| 609 | if ( !post_data ) | 
|---|
| 610 | break;  /* we are done */ | 
|---|
| 611 |  | 
|---|
| 612 | code = (*post_data)[0]; | 
|---|
| 613 |  | 
|---|
| 614 | if ( code != last_code ) | 
|---|
| 615 | { | 
|---|
| 616 | if ( code == 5 ) | 
|---|
| 617 | total_size += 2; /* just the end code */ | 
|---|
| 618 | else | 
|---|
| 619 | total_size += 6; /* code + 4 bytes chunk length */ | 
|---|
| 620 | } | 
|---|
| 621 |  | 
|---|
| 622 | total_size += (FT_ULong)GetHandleSize( post_data ) - 2; | 
|---|
| 623 | last_code = code; | 
|---|
| 624 |  | 
|---|
| 625 | /* detect resource fork overflow */ | 
|---|
| 626 | if ( FT_MAC_RFORK_MAX_LEN < total_size ) | 
|---|
| 627 | { | 
|---|
| 628 | error = FT_THROW( Array_Too_Large ); | 
|---|
| 629 | goto Error; | 
|---|
| 630 | } | 
|---|
| 631 |  | 
|---|
| 632 | old_total_size = total_size; | 
|---|
| 633 | } | 
|---|
| 634 |  | 
|---|
| 635 | if ( FT_ALLOC( buffer, (FT_Long)total_size ) ) | 
|---|
| 636 | goto Error; | 
|---|
| 637 |  | 
|---|
| 638 | /* Second pass: append all POST data to the buffer, add PFB fields. */ | 
|---|
| 639 | /* Glue all consecutive chunks of the same type together.           */ | 
|---|
| 640 | p              = buffer; | 
|---|
| 641 | res_id         = 501; | 
|---|
| 642 | last_code      = -1; | 
|---|
| 643 | pfb_chunk_size = 0; | 
|---|
| 644 |  | 
|---|
| 645 | for (;;) | 
|---|
| 646 | { | 
|---|
| 647 | post_data = Get1Resource( TTAG_POST, res_id++ ); | 
|---|
| 648 | if ( !post_data ) | 
|---|
| 649 | break;  /* we are done */ | 
|---|
| 650 |  | 
|---|
| 651 | post_size = (FT_ULong)GetHandleSize( post_data ) - 2; | 
|---|
| 652 | code = (*post_data)[0]; | 
|---|
| 653 |  | 
|---|
| 654 | if ( code != last_code ) | 
|---|
| 655 | { | 
|---|
| 656 | if ( last_code != -1 ) | 
|---|
| 657 | { | 
|---|
| 658 | /* we are done adding a chunk, fill in the size field */ | 
|---|
| 659 | if ( size_p ) | 
|---|
| 660 | { | 
|---|
| 661 | *size_p++ = (FT_Byte)(   pfb_chunk_size         & 0xFF ); | 
|---|
| 662 | *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8  ) & 0xFF ); | 
|---|
| 663 | *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF ); | 
|---|
| 664 | *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF ); | 
|---|
| 665 | } | 
|---|
| 666 | pfb_chunk_size = 0; | 
|---|
| 667 | } | 
|---|
| 668 |  | 
|---|
| 669 | *p++ = 0x80; | 
|---|
| 670 | if ( code == 5 ) | 
|---|
| 671 | *p++ = 0x03;  /* the end */ | 
|---|
| 672 | else if ( code == 2 ) | 
|---|
| 673 | *p++ = 0x02;  /* binary segment */ | 
|---|
| 674 | else | 
|---|
| 675 | *p++ = 0x01;  /* ASCII segment */ | 
|---|
| 676 |  | 
|---|
| 677 | if ( code != 5 ) | 
|---|
| 678 | { | 
|---|
| 679 | size_p = p;   /* save for later */ | 
|---|
| 680 | p += 4;       /* make space for size field */ | 
|---|
| 681 | } | 
|---|
| 682 | } | 
|---|
| 683 |  | 
|---|
| 684 | ft_memcpy( p, *post_data + 2, post_size ); | 
|---|
| 685 | pfb_chunk_size += post_size; | 
|---|
| 686 | p += post_size; | 
|---|
| 687 | last_code = code; | 
|---|
| 688 | } | 
|---|
| 689 |  | 
|---|
| 690 | *pfb_data = buffer; | 
|---|
| 691 | *size = total_size; | 
|---|
| 692 |  | 
|---|
| 693 | Error: | 
|---|
| 694 | CloseResFile( res ); | 
|---|
| 695 | return error; | 
|---|
| 696 | } | 
|---|
| 697 |  | 
|---|
| 698 |  | 
|---|
| 699 | /* Create a new FT_Face from a file path to an LWFN file. */ | 
|---|
| 700 | static FT_Error | 
|---|
| 701 | FT_New_Face_From_LWFN( FT_Library    library, | 
|---|
| 702 | const UInt8*  pathname, | 
|---|
| 703 | FT_Long       face_index, | 
|---|
| 704 | FT_Face*      aface ) | 
|---|
| 705 | { | 
|---|
| 706 | FT_Byte*       pfb_data; | 
|---|
| 707 | FT_ULong       pfb_size; | 
|---|
| 708 | FT_Error       error; | 
|---|
| 709 | ResFileRefNum  res; | 
|---|
| 710 |  | 
|---|
| 711 |  | 
|---|
| 712 | if ( noErr != FT_FSPathMakeRes( pathname, &res ) ) | 
|---|
| 713 | return FT_THROW( Cannot_Open_Resource ); | 
|---|
| 714 |  | 
|---|
| 715 | pfb_data = NULL; | 
|---|
| 716 | pfb_size = 0; | 
|---|
| 717 | error = read_lwfn( library->memory, res, &pfb_data, &pfb_size ); | 
|---|
| 718 | CloseResFile( res ); /* PFB is already loaded, useless anymore */ | 
|---|
| 719 | if ( error ) | 
|---|
| 720 | return error; | 
|---|
| 721 |  | 
|---|
| 722 | return open_face_from_buffer( library, | 
|---|
| 723 | pfb_data, | 
|---|
| 724 | pfb_size, | 
|---|
| 725 | face_index, | 
|---|
| 726 | "type1", | 
|---|
| 727 | aface ); | 
|---|
| 728 | } | 
|---|
| 729 |  | 
|---|
| 730 |  | 
|---|
| 731 | /* Create a new FT_Face from an SFNT resource, specified by res ID. */ | 
|---|
| 732 | static FT_Error | 
|---|
| 733 | FT_New_Face_From_SFNT( FT_Library  library, | 
|---|
| 734 | ResID       sfnt_id, | 
|---|
| 735 | FT_Long     face_index, | 
|---|
| 736 | FT_Face*    aface ) | 
|---|
| 737 | { | 
|---|
| 738 | Handle     sfnt = NULL; | 
|---|
| 739 | FT_Byte*   sfnt_data; | 
|---|
| 740 | size_t     sfnt_size; | 
|---|
| 741 | FT_Error   error  = FT_Err_Ok; | 
|---|
| 742 | FT_Memory  memory = library->memory; | 
|---|
| 743 | int        is_cff, is_sfnt_ps; | 
|---|
| 744 |  | 
|---|
| 745 |  | 
|---|
| 746 | sfnt = GetResource( TTAG_sfnt, sfnt_id ); | 
|---|
| 747 | if ( !sfnt ) | 
|---|
| 748 | return FT_THROW( Invalid_Handle ); | 
|---|
| 749 |  | 
|---|
| 750 | sfnt_size = (FT_ULong)GetHandleSize( sfnt ); | 
|---|
| 751 |  | 
|---|
| 752 | /* detect resource fork overflow */ | 
|---|
| 753 | if ( FT_MAC_RFORK_MAX_LEN < sfnt_size ) | 
|---|
| 754 | return FT_THROW( Array_Too_Large ); | 
|---|
| 755 |  | 
|---|
| 756 | if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) ) | 
|---|
| 757 | { | 
|---|
| 758 | ReleaseResource( sfnt ); | 
|---|
| 759 | return error; | 
|---|
| 760 | } | 
|---|
| 761 |  | 
|---|
| 762 | ft_memcpy( sfnt_data, *sfnt, sfnt_size ); | 
|---|
| 763 | ReleaseResource( sfnt ); | 
|---|
| 764 |  | 
|---|
| 765 | is_cff     = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); | 
|---|
| 766 | is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 ); | 
|---|
| 767 |  | 
|---|
| 768 | if ( is_sfnt_ps ) | 
|---|
| 769 | { | 
|---|
| 770 | FT_Stream  stream; | 
|---|
| 771 |  | 
|---|
| 772 |  | 
|---|
| 773 | if ( FT_NEW( stream ) ) | 
|---|
| 774 | goto Try_OpenType; | 
|---|
| 775 |  | 
|---|
| 776 | FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size ); | 
|---|
| 777 | if ( !open_face_PS_from_sfnt_stream( library, | 
|---|
| 778 | stream, | 
|---|
| 779 | face_index, | 
|---|
| 780 | 0, NULL, | 
|---|
| 781 | aface ) ) | 
|---|
| 782 | { | 
|---|
| 783 | FT_Stream_Close( stream ); | 
|---|
| 784 | FT_FREE( stream ); | 
|---|
| 785 | FT_FREE( sfnt_data ); | 
|---|
| 786 | goto Exit; | 
|---|
| 787 | } | 
|---|
| 788 |  | 
|---|
| 789 | FT_FREE( stream ); | 
|---|
| 790 | } | 
|---|
| 791 | Try_OpenType: | 
|---|
| 792 | error = open_face_from_buffer( library, | 
|---|
| 793 | sfnt_data, | 
|---|
| 794 | sfnt_size, | 
|---|
| 795 | face_index, | 
|---|
| 796 | is_cff ? "cff": "truetype", | 
|---|
| 797 | aface ); | 
|---|
| 798 | Exit: | 
|---|
| 799 | return error; | 
|---|
| 800 | } | 
|---|
| 801 |  | 
|---|
| 802 |  | 
|---|
| 803 | /* Create a new FT_Face from a file path to a suitcase file. */ | 
|---|
| 804 | static FT_Error | 
|---|
| 805 | FT_New_Face_From_Suitcase( FT_Library    library, | 
|---|
| 806 | const UInt8*  pathname, | 
|---|
| 807 | FT_Long       face_index, | 
|---|
| 808 | FT_Face*      aface ) | 
|---|
| 809 | { | 
|---|
| 810 | FT_Error       error = FT_ERR( Cannot_Open_Resource ); | 
|---|
| 811 | ResFileRefNum  res_ref; | 
|---|
| 812 | ResourceIndex  res_index; | 
|---|
| 813 | Handle         fond; | 
|---|
| 814 | short          num_faces_in_res; | 
|---|
| 815 |  | 
|---|
| 816 |  | 
|---|
| 817 | if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) ) | 
|---|
| 818 | return FT_THROW( Cannot_Open_Resource ); | 
|---|
| 819 |  | 
|---|
| 820 | UseResFile( res_ref ); | 
|---|
| 821 | if ( ResError() ) | 
|---|
| 822 | return FT_THROW( Cannot_Open_Resource ); | 
|---|
| 823 |  | 
|---|
| 824 | num_faces_in_res = 0; | 
|---|
| 825 | for ( res_index = 1; ; res_index++ ) | 
|---|
| 826 | { | 
|---|
| 827 | short  num_faces_in_fond; | 
|---|
| 828 |  | 
|---|
| 829 |  | 
|---|
| 830 | fond = Get1IndResource( TTAG_FOND, res_index ); | 
|---|
| 831 | if ( ResError() ) | 
|---|
| 832 | break; | 
|---|
| 833 |  | 
|---|
| 834 | num_faces_in_fond  = count_faces( fond, pathname ); | 
|---|
| 835 | num_faces_in_res  += num_faces_in_fond; | 
|---|
| 836 |  | 
|---|
| 837 | if ( 0 <= face_index && face_index < num_faces_in_fond && error ) | 
|---|
| 838 | error = FT_New_Face_From_FOND( library, fond, face_index, aface ); | 
|---|
| 839 |  | 
|---|
| 840 | face_index -= num_faces_in_fond; | 
|---|
| 841 | } | 
|---|
| 842 |  | 
|---|
| 843 | CloseResFile( res_ref ); | 
|---|
| 844 | if ( !error && aface && *aface ) | 
|---|
| 845 | (*aface)->num_faces = num_faces_in_res; | 
|---|
| 846 | return error; | 
|---|
| 847 | } | 
|---|
| 848 |  | 
|---|
| 849 |  | 
|---|
| 850 | /* documentation is in ftmac.h */ | 
|---|
| 851 |  | 
|---|
| 852 | FT_EXPORT_DEF( FT_Error ) | 
|---|
| 853 | FT_New_Face_From_FOND( FT_Library  library, | 
|---|
| 854 | Handle      fond, | 
|---|
| 855 | FT_Long     face_index, | 
|---|
| 856 | FT_Face*    aface ) | 
|---|
| 857 | { | 
|---|
| 858 | short     have_sfnt, have_lwfn = 0; | 
|---|
| 859 | ResID     sfnt_id, fond_id; | 
|---|
| 860 | OSType    fond_type; | 
|---|
| 861 | Str255    fond_name; | 
|---|
| 862 | Str255    lwfn_file_name; | 
|---|
| 863 | UInt8     path_lwfn[PATH_MAX]; | 
|---|
| 864 | OSErr     err; | 
|---|
| 865 | FT_Error  error = FT_Err_Ok; | 
|---|
| 866 |  | 
|---|
| 867 |  | 
|---|
| 868 | /* check of `library' and `aface' delayed to `FT_New_Face_From_XXX' */ | 
|---|
| 869 |  | 
|---|
| 870 | GetResInfo( fond, &fond_id, &fond_type, fond_name ); | 
|---|
| 871 | if ( ResError() != noErr || fond_type != TTAG_FOND ) | 
|---|
| 872 | return FT_THROW( Invalid_File_Format ); | 
|---|
| 873 |  | 
|---|
| 874 | parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index ); | 
|---|
| 875 |  | 
|---|
| 876 | if ( lwfn_file_name[0] ) | 
|---|
| 877 | { | 
|---|
| 878 | ResFileRefNum  res; | 
|---|
| 879 |  | 
|---|
| 880 |  | 
|---|
| 881 | res = HomeResFile( fond ); | 
|---|
| 882 | if ( noErr != ResError() ) | 
|---|
| 883 | goto found_no_lwfn_file; | 
|---|
| 884 |  | 
|---|
| 885 | { | 
|---|
| 886 | UInt8  path_fond[PATH_MAX]; | 
|---|
| 887 | FSRef  ref; | 
|---|
| 888 |  | 
|---|
| 889 |  | 
|---|
| 890 | err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum, | 
|---|
| 891 | NULL, NULL, NULL, &ref, NULL ); | 
|---|
| 892 | if ( noErr != err ) | 
|---|
| 893 | goto found_no_lwfn_file; | 
|---|
| 894 |  | 
|---|
| 895 | err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) ); | 
|---|
| 896 | if ( noErr != err ) | 
|---|
| 897 | goto found_no_lwfn_file; | 
|---|
| 898 |  | 
|---|
| 899 | error = lookup_lwfn_by_fond( path_fond, lwfn_file_name, | 
|---|
| 900 | path_lwfn, sizeof ( path_lwfn ) ); | 
|---|
| 901 | if ( !error ) | 
|---|
| 902 | have_lwfn = 1; | 
|---|
| 903 | } | 
|---|
| 904 | } | 
|---|
| 905 |  | 
|---|
| 906 | if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) | 
|---|
| 907 | error = FT_New_Face_From_LWFN( library, | 
|---|
| 908 | path_lwfn, | 
|---|
| 909 | face_index, | 
|---|
| 910 | aface ); | 
|---|
| 911 | else | 
|---|
| 912 | error = FT_THROW( Unknown_File_Format ); | 
|---|
| 913 |  | 
|---|
| 914 | found_no_lwfn_file: | 
|---|
| 915 | if ( have_sfnt && error ) | 
|---|
| 916 | error = FT_New_Face_From_SFNT( library, | 
|---|
| 917 | sfnt_id, | 
|---|
| 918 | face_index, | 
|---|
| 919 | aface ); | 
|---|
| 920 |  | 
|---|
| 921 | return error; | 
|---|
| 922 | } | 
|---|
| 923 |  | 
|---|
| 924 |  | 
|---|
| 925 | /* Common function to load a new FT_Face from a resource file. */ | 
|---|
| 926 | static FT_Error | 
|---|
| 927 | FT_New_Face_From_Resource( FT_Library    library, | 
|---|
| 928 | const UInt8*  pathname, | 
|---|
| 929 | FT_Long       face_index, | 
|---|
| 930 | FT_Face*      aface ) | 
|---|
| 931 | { | 
|---|
| 932 | OSType    file_type; | 
|---|
| 933 | FT_Error  error; | 
|---|
| 934 |  | 
|---|
| 935 |  | 
|---|
| 936 | /* LWFN is a (very) specific file format, check for it explicitly */ | 
|---|
| 937 | file_type = get_file_type_from_path( pathname ); | 
|---|
| 938 | if ( file_type == TTAG_LWFN ) | 
|---|
| 939 | return FT_New_Face_From_LWFN( library, pathname, face_index, aface ); | 
|---|
| 940 |  | 
|---|
| 941 | /* Otherwise the file type doesn't matter (there are more than  */ | 
|---|
| 942 | /* `FFIL' and `tfil').  Just try opening it as a font suitcase; */ | 
|---|
| 943 | /* if it works, fine.                                           */ | 
|---|
| 944 |  | 
|---|
| 945 | error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface ); | 
|---|
| 946 | if ( error ) | 
|---|
| 947 | { | 
|---|
| 948 | /* let it fall through to normal loader (.ttf, .otf, etc.); */ | 
|---|
| 949 | /* we signal this by returning no error and no FT_Face      */ | 
|---|
| 950 | *aface = NULL; | 
|---|
| 951 | } | 
|---|
| 952 |  | 
|---|
| 953 | return FT_Err_Ok; | 
|---|
| 954 | } | 
|---|
| 955 |  | 
|---|
| 956 |  | 
|---|
| 957 | /*************************************************************************/ | 
|---|
| 958 | /*                                                                       */ | 
|---|
| 959 | /* <Function>                                                            */ | 
|---|
| 960 | /*    FT_New_Face                                                        */ | 
|---|
| 961 | /*                                                                       */ | 
|---|
| 962 | /* <Description>                                                         */ | 
|---|
| 963 | /*    This is the Mac-specific implementation of FT_New_Face.  In        */ | 
|---|
| 964 | /*    addition to the standard FT_New_Face() functionality, it also      */ | 
|---|
| 965 | /*    accepts pathnames to Mac suitcase files.  For further              */ | 
|---|
| 966 | /*    documentation see the original FT_New_Face() in freetype.h.        */ | 
|---|
| 967 | /*                                                                       */ | 
|---|
| 968 | FT_EXPORT_DEF( FT_Error ) | 
|---|
| 969 | FT_New_Face( FT_Library   library, | 
|---|
| 970 | const char*  pathname, | 
|---|
| 971 | FT_Long      face_index, | 
|---|
| 972 | FT_Face*     aface ) | 
|---|
| 973 | { | 
|---|
| 974 | FT_Open_Args  args; | 
|---|
| 975 | FT_Error      error; | 
|---|
| 976 |  | 
|---|
| 977 |  | 
|---|
| 978 | /* test for valid `library' and `aface' delayed to FT_Open_Face() */ | 
|---|
| 979 | if ( !pathname ) | 
|---|
| 980 | return FT_THROW( Invalid_Argument ); | 
|---|
| 981 |  | 
|---|
| 982 | *aface = NULL; | 
|---|
| 983 |  | 
|---|
| 984 | /* try resourcefork based font: LWFN, FFIL */ | 
|---|
| 985 | error = FT_New_Face_From_Resource( library, (UInt8 *)pathname, | 
|---|
| 986 | face_index, aface ); | 
|---|
| 987 | if ( error || *aface ) | 
|---|
| 988 | return error; | 
|---|
| 989 |  | 
|---|
| 990 | /* let it fall through to normal loader (.ttf, .otf, etc.) */ | 
|---|
| 991 | args.flags    = FT_OPEN_PATHNAME; | 
|---|
| 992 | args.pathname = (char*)pathname; | 
|---|
| 993 |  | 
|---|
| 994 | return FT_Open_Face( library, &args, face_index, aface ); | 
|---|
| 995 | } | 
|---|
| 996 |  | 
|---|
| 997 |  | 
|---|
| 998 | /*************************************************************************/ | 
|---|
| 999 | /*                                                                       */ | 
|---|
| 1000 | /* <Function>                                                            */ | 
|---|
| 1001 | /*    FT_New_Face_From_FSRef                                             */ | 
|---|
| 1002 | /*                                                                       */ | 
|---|
| 1003 | /* <Description>                                                         */ | 
|---|
| 1004 | /*    FT_New_Face_From_FSRef is identical to FT_New_Face except it       */ | 
|---|
| 1005 | /*    accepts an FSRef instead of a path.                                */ | 
|---|
| 1006 | /*                                                                       */ | 
|---|
| 1007 | /* This function is deprecated because Carbon data types (FSRef)         */ | 
|---|
| 1008 | /* are not cross-platform, and thus not suitable for the FreeType API.   */ | 
|---|
| 1009 | FT_EXPORT_DEF( FT_Error ) | 
|---|
| 1010 | FT_New_Face_From_FSRef( FT_Library    library, | 
|---|
| 1011 | const FSRef*  ref, | 
|---|
| 1012 | FT_Long       face_index, | 
|---|
| 1013 | FT_Face*      aface ) | 
|---|
| 1014 | { | 
|---|
| 1015 | FT_Error      error; | 
|---|
| 1016 | FT_Open_Args  args; | 
|---|
| 1017 |  | 
|---|
| 1018 | OSErr  err; | 
|---|
| 1019 | UInt8  pathname[PATH_MAX]; | 
|---|
| 1020 |  | 
|---|
| 1021 |  | 
|---|
| 1022 | /* check of `library' and `aface' delayed to */ | 
|---|
| 1023 | /* `FT_New_Face_From_Resource'               */ | 
|---|
| 1024 |  | 
|---|
| 1025 | if ( !ref ) | 
|---|
| 1026 | return FT_THROW( Invalid_Argument ); | 
|---|
| 1027 |  | 
|---|
| 1028 | err = FSRefMakePath( ref, pathname, sizeof ( pathname ) ); | 
|---|
| 1029 | if ( err ) | 
|---|
| 1030 | error = FT_THROW( Cannot_Open_Resource ); | 
|---|
| 1031 |  | 
|---|
| 1032 | error = FT_New_Face_From_Resource( library, pathname, face_index, aface ); | 
|---|
| 1033 | if ( error || *aface ) | 
|---|
| 1034 | return error; | 
|---|
| 1035 |  | 
|---|
| 1036 | /* fallback to datafork font */ | 
|---|
| 1037 | args.flags    = FT_OPEN_PATHNAME; | 
|---|
| 1038 | args.pathname = (char*)pathname; | 
|---|
| 1039 | return FT_Open_Face( library, &args, face_index, aface ); | 
|---|
| 1040 | } | 
|---|
| 1041 |  | 
|---|
| 1042 |  | 
|---|
| 1043 | /*************************************************************************/ | 
|---|
| 1044 | /*                                                                       */ | 
|---|
| 1045 | /* <Function>                                                            */ | 
|---|
| 1046 | /*    FT_New_Face_From_FSSpec                                            */ | 
|---|
| 1047 | /*                                                                       */ | 
|---|
| 1048 | /* <Description>                                                         */ | 
|---|
| 1049 | /*    FT_New_Face_From_FSSpec is identical to FT_New_Face except it      */ | 
|---|
| 1050 | /*    accepts an FSSpec instead of a path.                               */ | 
|---|
| 1051 | /*                                                                       */ | 
|---|
| 1052 | /* This function is deprecated because FSSpec is deprecated in Mac OS X  */ | 
|---|
| 1053 | FT_EXPORT_DEF( FT_Error ) | 
|---|
| 1054 | FT_New_Face_From_FSSpec( FT_Library     library, | 
|---|
| 1055 | const FSSpec*  spec, | 
|---|
| 1056 | FT_Long        face_index, | 
|---|
| 1057 | FT_Face*       aface ) | 
|---|
| 1058 | { | 
|---|
| 1059 | #if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \ | 
|---|
| 1060 | ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) ) | 
|---|
| 1061 | FT_UNUSED( library ); | 
|---|
| 1062 | FT_UNUSED( spec ); | 
|---|
| 1063 | FT_UNUSED( face_index ); | 
|---|
| 1064 | FT_UNUSED( aface ); | 
|---|
| 1065 |  | 
|---|
| 1066 | return FT_THROW( Unimplemented_Feature ); | 
|---|
| 1067 | #else | 
|---|
| 1068 | FSRef  ref; | 
|---|
| 1069 |  | 
|---|
| 1070 |  | 
|---|
| 1071 | /* check of `library' and `aface' delayed to `FT_New_Face_From_FSRef' */ | 
|---|
| 1072 |  | 
|---|
| 1073 | if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr ) | 
|---|
| 1074 | return FT_THROW( Invalid_Argument ); | 
|---|
| 1075 | else | 
|---|
| 1076 | return FT_New_Face_From_FSRef( library, &ref, face_index, aface ); | 
|---|
| 1077 | #endif | 
|---|
| 1078 | } | 
|---|
| 1079 |  | 
|---|
| 1080 | #else /* !FT_MACINTOSH */ | 
|---|
| 1081 |  | 
|---|
| 1082 | /* ANSI C doesn't like empty source files */ | 
|---|
| 1083 | typedef int  _ft_mac_dummy; | 
|---|
| 1084 |  | 
|---|
| 1085 | #endif /* !FT_MACINTOSH */ | 
|---|
| 1086 |  | 
|---|
| 1087 |  | 
|---|
| 1088 | /* END */ | 
|---|
| 1089 |  | 
|---|