mirror of
https://github.com/gnustep/libs-back.git
synced 2025-02-23 11:51:27 +00:00
Rewrite font system to cache fonts in a plist and support nfont bundles.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@25717 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
2cc8536f04
commit
2d50c93089
5 changed files with 781 additions and 164 deletions
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
|||
2007-12-10 Isaiah Beerbower <public@ipaqah.com>
|
||||
|
||||
* Source/cairo/CairoFontEnumerator.m (-enumerateFontsAndFamilies, cacheFolder,
|
||||
bundleModificationDate, cacheFont, cacheNFontBundle, mergeFontInfo):
|
||||
Rewrite to cache fonts in a plist and support nfont bundles.
|
||||
(-defaultSystemFontName, -defaultBoldSystemFontName,
|
||||
-defaultFixedPitchFontName):
|
||||
Added actual PostScript name for Bitstream Vera fonts.
|
||||
* Source/cairo/CairoFaceInfo.m (-fontFace,
|
||||
-initWithfamilyName:fullName:weight:italicAngle:traits:files:index:,
|
||||
-setFullName:, -fullName, -setItalicAngle:, -italicAngle, -setIndex:, -index):
|
||||
Update to reflect changes in CairoFontEnumerator.
|
||||
* Headers/cairo/CairoFaceInfo.m: Same.
|
||||
* Source/cairo/CairoFontInfo.m (-setupAttributes): Take italicAngle & fullName
|
||||
from CairoFaceInfo.
|
||||
|
||||
2007-12-10 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Source/xlib/GSXftFontInfo.m:
|
||||
|
|
|
@ -39,28 +39,47 @@
|
|||
@interface CairoFaceInfo : NSObject
|
||||
{
|
||||
int _weight;
|
||||
float _italicAngle;
|
||||
unsigned int _traits;
|
||||
|
||||
FT_Library _ftlibrary;
|
||||
FT_Face _ftface;
|
||||
|
||||
cairo_font_face_t *_fontFace;
|
||||
FcPattern *_pattern;
|
||||
cairo_font_face_t *_fontFace;
|
||||
|
||||
NSArray *_filePaths;
|
||||
int _indexInFile;
|
||||
|
||||
NSString *_familyName;
|
||||
NSString *_fullName;
|
||||
}
|
||||
|
||||
- (id) initWithfamilyName: (NSString *)familyName
|
||||
- (id) initWithfamilyName: (NSString *)familyName
|
||||
fullName: (NSString *)fullName
|
||||
weight: (int)weight
|
||||
italicAngle: (float)italicAngle
|
||||
traits: (unsigned int)traits
|
||||
pattern: (FcPattern *)pattern;
|
||||
files: (NSArray *)paths
|
||||
index: (int)index;
|
||||
|
||||
- (unsigned int) cacheSize;
|
||||
|
||||
- (int) weight;
|
||||
- (void) setWeight: (int)weight;
|
||||
- (int) italicAngle;
|
||||
- (void) setItalicAngle: (float)italicAngle;
|
||||
- (unsigned int) traits;
|
||||
- (void) setTraits: (unsigned int)traits;
|
||||
|
||||
- (NSString *) familyName;
|
||||
- (void) setFamilyName: (NSString *)name;
|
||||
- (NSString *)fullName;
|
||||
- (void) setFullName: (NSString *)name;
|
||||
|
||||
- (void) setFiles: (NSArray *)path;
|
||||
- (NSArray *)files;
|
||||
- (void) setIndex: (int)index;
|
||||
- (int)index;
|
||||
|
||||
- (cairo_font_face_t *)fontFace;
|
||||
|
||||
|
|
|
@ -32,21 +32,27 @@
|
|||
#include <cairo-ft.h>
|
||||
#include <AppKit/NSFontManager.h>
|
||||
|
||||
@ implementation CairoFaceInfo
|
||||
@implementation CairoFaceInfo
|
||||
|
||||
- (id) initWithfamilyName: (NSString *)familyName
|
||||
- (id) initWithfamilyName: (NSString *)familyName
|
||||
fullName: (NSString *)fullName
|
||||
weight: (int)weight
|
||||
italicAngle: (float)italicAngle
|
||||
traits: (unsigned int)traits
|
||||
pattern: (FcPattern *)pattern
|
||||
files: (NSArray *)paths
|
||||
index: (int)index
|
||||
{
|
||||
_pattern = pattern;
|
||||
FcPatternReference(_pattern);
|
||||
[super init];
|
||||
|
||||
[self setFamilyName: familyName];
|
||||
[self setFullName: fullName];
|
||||
[self setWeight: weight];
|
||||
[self setItalicAngle: italicAngle];
|
||||
[self setTraits: traits];
|
||||
|
||||
return self;
|
||||
[self setFiles: paths];
|
||||
[self setIndex: index];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
|
@ -55,20 +61,38 @@
|
|||
{
|
||||
cairo_font_face_destroy(_fontFace);
|
||||
}
|
||||
FcPatternDestroy(_pattern);
|
||||
if (_ftface)
|
||||
{
|
||||
FT_Done_Face(_ftface);
|
||||
}
|
||||
if (_ftlibrary)
|
||||
{
|
||||
FT_Done_FreeType(_ftlibrary);
|
||||
}
|
||||
RELEASE(_familyName);
|
||||
RELEASE(_filePaths);
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString *)familyName
|
||||
{
|
||||
return _familyName;
|
||||
}
|
||||
|
||||
- (void) setFamilyName: (NSString *)name
|
||||
{
|
||||
ASSIGN(_familyName, name);
|
||||
}
|
||||
|
||||
- (NSString *)familyName
|
||||
- (NSString *)fullName
|
||||
{
|
||||
return _familyName;
|
||||
return _fullName;
|
||||
}
|
||||
|
||||
- (void) setFullName: (NSString *)name
|
||||
{
|
||||
ASSIGN(_fullName, name);
|
||||
}
|
||||
|
||||
- (int) weight
|
||||
|
@ -81,6 +105,16 @@
|
|||
_weight = weight;
|
||||
}
|
||||
|
||||
- (int) italicAngle
|
||||
{
|
||||
return _italicAngle;
|
||||
}
|
||||
|
||||
- (void) setItalicAngle: (float)italicAngle
|
||||
{
|
||||
_italicAngle = italicAngle;
|
||||
}
|
||||
|
||||
- (unsigned int) traits
|
||||
{
|
||||
return _traits;
|
||||
|
@ -96,26 +130,79 @@
|
|||
return 257;
|
||||
}
|
||||
|
||||
- (void) setFiles: (NSArray *)paths
|
||||
{
|
||||
ASSIGN(_filePaths, paths);
|
||||
}
|
||||
|
||||
- (NSArray *)files
|
||||
{
|
||||
return _filePaths;
|
||||
}
|
||||
|
||||
- (void) setIndex: (int)index
|
||||
{
|
||||
_indexInFile = index;
|
||||
}
|
||||
|
||||
- (int)index
|
||||
{
|
||||
return _indexInFile;
|
||||
}
|
||||
|
||||
- (cairo_font_face_t *)fontFace
|
||||
{
|
||||
if (!_fontFace)
|
||||
{
|
||||
FcResult result;
|
||||
FcPattern *resolved;
|
||||
|
||||
FcConfigSubstitute (NULL, _pattern, FcMatchPattern);
|
||||
FcDefaultSubstitute(_pattern);
|
||||
resolved = FcFontMatch(NULL, _pattern, &result);
|
||||
|
||||
_fontFace = cairo_ft_font_face_create_for_pattern(resolved);
|
||||
FcPatternDestroy(resolved);
|
||||
|
||||
const char *cPath;
|
||||
int i;
|
||||
int count;
|
||||
|
||||
/* FIXME: There should only be one FT_Library for all faces. */
|
||||
if (!_ftlibrary)
|
||||
{
|
||||
FT_Init_FreeType(&_ftlibrary);
|
||||
}
|
||||
|
||||
if (! _ftface)
|
||||
{
|
||||
count = [_filePaths count];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
cPath = [[_filePaths objectAtIndex: i] UTF8String];
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
if (FT_Attach_File(_ftface, cPath) != 0)
|
||||
NSLog(@"Could not attach %@ to font face.",
|
||||
[_filePaths objectAtIndex: i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FT_New_Face(_ftlibrary, cPath, _indexInFile, &_ftface) != 0)
|
||||
{
|
||||
NSLog(@"Creating a font face failed %@", _familyName);
|
||||
_ftface = NULL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_fontFace =
|
||||
cairo_ft_font_face_create_for_ft_face(_ftface, FT_LOAD_DEFAULT);
|
||||
|
||||
if ((!_fontFace)
|
||||
|| (cairo_font_face_status(_fontFace) != CAIRO_STATUS_SUCCESS))
|
||||
{
|
||||
NSLog(@"Creating a font face failed %@", _familyName);
|
||||
cairo_font_face_destroy(_fontFace);
|
||||
|
||||
FT_Done_Face(_ftface);
|
||||
FT_Done_FreeType(_ftlibrary);
|
||||
|
||||
_fontFace = NULL;
|
||||
_ftface = NULL;
|
||||
_ftlibrary = NULL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
Base on original code of Alex Malmberg
|
||||
Rewrite: Fred Kiefer <fredkiefer@gmx.de>
|
||||
Date: Jan 2006
|
||||
Rewrite: Isaiah Beerbower <public@ipaqah.com>
|
||||
Date: Dec 2007
|
||||
|
||||
This file is part of GNUstep.
|
||||
|
||||
|
@ -46,10 +48,631 @@
|
|||
#include "cairo/CairoFontEnumerator.h"
|
||||
#include "cairo/CairoFontInfo.h"
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_TYPE1_TABLES_H
|
||||
#include FT_TRUETYPE_TABLES_H
|
||||
#include FT_BDF_H
|
||||
#include FT_SFNT_NAMES_H
|
||||
#include FT_TRUETYPE_IDS_H
|
||||
|
||||
|
||||
@implementation CairoFontEnumerator
|
||||
|
||||
NSMutableDictionary * __allFonts;
|
||||
|
||||
|
||||
void mergeFontInfo(NSMutableDictionary *fontInfo, NSMutableArray *fontCache)
|
||||
{
|
||||
NSString *primaryFile;
|
||||
int i;
|
||||
int count = [fontCache count];
|
||||
|
||||
primaryFile = [[fontInfo objectForKey: @"Files"] objectAtIndex: 0];
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
NSDictionary *prevFontInfo = [fontCache objectAtIndex: i];
|
||||
NSArray *files = [prevFontInfo objectForKey: @"Files"];
|
||||
|
||||
if (files != nil && [files count] > 0)
|
||||
{
|
||||
int f_i;
|
||||
int f_count = [files count];
|
||||
|
||||
for (f_i = 0; f_i < f_count; f_i++)
|
||||
{
|
||||
if ([[[files objectAtIndex: f_i] stringByExpandingTildeInPath]
|
||||
isEqual: primaryFile])
|
||||
{
|
||||
[fontInfo addEntriesFromDictionary: prevFontInfo];
|
||||
[fontCache replaceObjectAtIndex: i withObject: fontInfo];
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[fontCache addObject: fontInfo];
|
||||
}
|
||||
|
||||
BOOL cacheNFontBundle(NSString *path,
|
||||
NSMutableArray *fontCache,
|
||||
BOOL mergeCache)
|
||||
{
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
NSString *fontInfoPath =
|
||||
[path stringByAppendingPathComponent: @"FontInfo.plist"];
|
||||
NSDictionary *fontInfo;
|
||||
NSArray *faces;
|
||||
|
||||
if (! [fm fileExistsAtPath: fontInfoPath])
|
||||
return NO;
|
||||
|
||||
fontInfo = [NSDictionary dictionaryWithContentsOfFile: fontInfoPath];
|
||||
if (fontInfo == nil)
|
||||
return NO;
|
||||
|
||||
faces = [fontInfo objectForKey: @"Faces"];
|
||||
if (faces == nil || [faces isKindOfClass: [NSArray class]] == NO)
|
||||
return NO;
|
||||
|
||||
int i;
|
||||
int count = [faces count];
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
NSMutableDictionary *face = [faces objectAtIndex: i];
|
||||
|
||||
NSMutableArray *files = [face objectForKey: @"Files"];
|
||||
if (files == nil || [files count] == 0)
|
||||
continue;
|
||||
|
||||
int f_i;
|
||||
int f_count = [files count];
|
||||
|
||||
for (f_i = 0; f_i < f_count; f_i++)
|
||||
{
|
||||
NSString *fontFilePath =
|
||||
[path stringByAppendingPathComponent: [files objectAtIndex: f_i]];
|
||||
|
||||
[files replaceObjectAtIndex: f_i withObject: fontFilePath];
|
||||
}
|
||||
|
||||
if ([fontInfo objectForKey: @"Family"] == nil)
|
||||
{
|
||||
NSString *familyName =
|
||||
[[path lastPathComponent] stringByDeletingPathExtension];
|
||||
|
||||
[face setObject: familyName forKey: @"Family"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[face setObject: [fontInfo objectForKey: @"Family"] forKey: @"Family"];
|
||||
}
|
||||
|
||||
if ([fontInfo objectForKey: @"Foundry"] != nil)
|
||||
{
|
||||
[face setObject: [fontInfo objectForKey: @"Foundry"] forKey: @"Foundry"];
|
||||
}
|
||||
|
||||
if ([fontInfo objectForKey: @"FontLicense"] != nil)
|
||||
{
|
||||
[face setObject: [fontInfo objectForKey: @"FontLicense"]
|
||||
forKey: @"FontLicense"];
|
||||
}
|
||||
|
||||
if ([fontInfo objectForKey: @"FontCopyright"] != nil)
|
||||
{
|
||||
[face setObject: [fontInfo objectForKey: @"FontCopyright"]
|
||||
forKey: @"FontCopyright"];
|
||||
}
|
||||
|
||||
if (mergeCache)
|
||||
mergeFontInfo(face, fontCache);
|
||||
else
|
||||
[fontCache addObject: face];
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
void cacheFont(NSString *path,
|
||||
NSMutableArray *fontCache,
|
||||
BOOL mergeCache,
|
||||
FT_Library library)
|
||||
{
|
||||
const char *cPath;
|
||||
int i;
|
||||
int facesCount;
|
||||
|
||||
path = [path stringByExpandingTildeInPath];
|
||||
cPath = [path UTF8String];
|
||||
|
||||
facesCount = 1;
|
||||
for (i = 0; i < facesCount; ++i)
|
||||
{
|
||||
FT_Face face;
|
||||
PS_FontInfoRec PSInfo;
|
||||
TT_Postscript *TTPSTable;
|
||||
TT_OS2 *TTOS2Table;
|
||||
int weight = 5;
|
||||
NSFontTraitMask traits = 0;
|
||||
NSMutableString *style;
|
||||
NSMutableArray *files;
|
||||
|
||||
if (FT_New_Face(library, cPath, 0, &face) == 0)
|
||||
{
|
||||
facesCount = face->num_faces;
|
||||
|
||||
if (!FT_IS_SCALABLE(face))
|
||||
{
|
||||
FT_Done_Face(face);
|
||||
continue;
|
||||
}
|
||||
|
||||
NSMutableDictionary *faceInfo = [[NSMutableDictionary alloc] init];
|
||||
const char *cString;
|
||||
|
||||
files = [NSMutableArray arrayWithObject: path];
|
||||
[faceInfo setObject: files forKey: @"Files"];
|
||||
|
||||
NSArray *f_extensions = [[NSArray alloc]
|
||||
initWithObjects: @"pfa", @"PFA", @"pfb", @"PFB", nil];
|
||||
if ([f_extensions containsObject: [path pathExtension]]
|
||||
/*FIXME: This would be a better way to check the
|
||||
font type, but it requires a later version of
|
||||
FreeType than I currently have installed - ipaqah*/
|
||||
/*strcmp(FT_Get_X11_Font_Format(face), "Type 1") == 0*/)
|
||||
{
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSArray *extensions = [[NSArray alloc]
|
||||
initWithObjects: @"afm", @"AFM", @"pfm", @"PFM", nil];
|
||||
|
||||
int m_i;
|
||||
int m_count = [extensions count];
|
||||
|
||||
for (m_i = 0; m_i < m_count; ++m_i)
|
||||
{
|
||||
NSString *metricsPath;
|
||||
|
||||
metricsPath = [[path stringByDeletingPathExtension]
|
||||
stringByAppendingPathExtension: [extensions objectAtIndex: m_i]];
|
||||
|
||||
cString = [metricsPath UTF8String];
|
||||
|
||||
if ([fm fileExistsAtPath: metricsPath] == NO)
|
||||
continue;
|
||||
|
||||
if (FT_Attach_File(face, cString) == 0)
|
||||
{
|
||||
[files addObject: metricsPath];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[faceInfo setObject: [NSNumber numberWithInt: i]
|
||||
forKey: @"Index"];
|
||||
|
||||
[faceInfo setObject: [NSString stringWithUTF8String: face->family_name]
|
||||
forKey: @"Family"];
|
||||
|
||||
if ((face->style_flags | FT_STYLE_FLAG_ITALIC) == face->style_flags)
|
||||
traits |= NSItalicFontMask;
|
||||
|
||||
if ((face->style_flags | FT_STYLE_FLAG_BOLD) == face->style_flags)
|
||||
{
|
||||
traits |= NSBoldFontMask;
|
||||
weight = 8;
|
||||
}
|
||||
|
||||
if (FT_Get_PS_Font_Info(face, &PSInfo) == 0)
|
||||
{
|
||||
[faceInfo setObject: [NSString stringWithUTF8String: PSInfo.full_name]
|
||||
forKey: @"FullName"];
|
||||
|
||||
[faceInfo setObject:
|
||||
[NSNumber numberWithFloat: (float)(PSInfo.italic_angle)]
|
||||
forKey: @"ItalicAngle"];
|
||||
|
||||
if (PSInfo.is_fixed_pitch)
|
||||
traits |= NSFixedPitchFontMask;
|
||||
}
|
||||
|
||||
if ((TTOS2Table = FT_Get_Sfnt_Table(face, ft_sfnt_os2)) != 0 &&
|
||||
TTOS2Table->version != 0xFFFF)
|
||||
{
|
||||
[faceInfo setObject:
|
||||
[NSString stringWithCString: (char *)TTOS2Table->achVendID
|
||||
length: 4]
|
||||
forKey: @"Foundry"];
|
||||
|
||||
if (TTOS2Table->usWeightClass == 0)
|
||||
weight = 5;
|
||||
else
|
||||
weight = (TTOS2Table->usWeightClass / 100) + 1;
|
||||
|
||||
if (TTOS2Table->usWidthClass > 0 && TTOS2Table->usWidthClass < 5)
|
||||
traits |= NSCondensedFontMask;
|
||||
else if (TTOS2Table->usWidthClass > 5)
|
||||
traits |= NSExpandedFontMask;
|
||||
}
|
||||
|
||||
if ((TTPSTable = FT_Get_Sfnt_Table(face, ft_sfnt_post)) != 0)
|
||||
{
|
||||
[faceInfo setObject: [NSNumber numberWithFloat:
|
||||
((float)(TTPSTable->italicAngle) / 65536.0)]
|
||||
forKey: @"ItalicAngle"];
|
||||
|
||||
if (TTPSTable->isFixedPitch)
|
||||
traits |= NSFixedPitchFontMask;
|
||||
}
|
||||
|
||||
if (face->style_name != NULL)
|
||||
{
|
||||
style = [NSString stringWithUTF8String: face->style_name];
|
||||
}
|
||||
else
|
||||
{
|
||||
style = [[NSMutableString alloc] init];
|
||||
|
||||
if ((traits | NSCondensedFontMask) == traits)
|
||||
{
|
||||
if ([style length] > 0)
|
||||
[style appendString: @" "];
|
||||
[style appendString: @"Condensed"];
|
||||
}
|
||||
else if ((traits | NSExpandedFontMask) == traits)
|
||||
{
|
||||
if ([style length] > 0)
|
||||
[style appendString: @" "];
|
||||
[style appendString: @"Expanded"];
|
||||
}
|
||||
|
||||
if ((traits | NSBoldFontMask) == traits)
|
||||
{
|
||||
if ([style length] > 0)
|
||||
[style appendString: @" "];
|
||||
[style appendString: @"Bold"];
|
||||
}
|
||||
|
||||
if ((traits | NSItalicFontMask) == traits)
|
||||
{
|
||||
if ([style length] > 0)
|
||||
[style appendString: @" "];
|
||||
[style appendString: @"Italic"];
|
||||
}
|
||||
|
||||
if (!([style length] > 0))
|
||||
[style appendString: @"Regular"];
|
||||
}
|
||||
[faceInfo setObject: style forKey: @"Name"];
|
||||
|
||||
if ((cString = FT_Get_Postscript_Name(face)) != NULL)
|
||||
[faceInfo setObject: [NSString stringWithUTF8String: cString]
|
||||
forKey: @"PostScriptName"];
|
||||
else
|
||||
[faceInfo setObject: [NSString stringWithFormat: @"%s-%@",
|
||||
face->family_name,
|
||||
style]
|
||||
forKey: @"PostScriptName"];
|
||||
|
||||
[faceInfo setObject: [NSNumber numberWithInt: weight]
|
||||
forKey: @"Weight"];
|
||||
|
||||
[faceInfo setObject: [NSNumber numberWithUnsignedLong: traits]
|
||||
forKey: @"Traits"];
|
||||
|
||||
FT_Done_Face(face);
|
||||
|
||||
if (mergeCache)
|
||||
mergeFontInfo(faceInfo, fontCache);
|
||||
else
|
||||
[fontCache addObject: faceInfo];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSDate *bundleModificationDate(NSString *path)
|
||||
{
|
||||
NSDate *date;
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
BOOL isDir;
|
||||
|
||||
NSArray *ls = [fm directoryContentsAtPath: path];
|
||||
int i;
|
||||
int count = [ls count];
|
||||
|
||||
date = [[fm fileAttributesAtPath: path
|
||||
traverseLink: YES] fileModificationDate];
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
NSString *subPath =
|
||||
[path stringByAppendingPathComponent: [ls objectAtIndex: i]];
|
||||
|
||||
if ([fm fileExistsAtPath: subPath isDirectory: &isDir] && isDir == YES)
|
||||
{
|
||||
date = [date laterDate: bundleModificationDate(subPath)];
|
||||
}
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
void cacheFolder(NSString *path,
|
||||
NSMutableArray *fontCache,
|
||||
NSMutableDictionary *cachedDirs,
|
||||
BOOL mergeCache,
|
||||
FT_Library library)
|
||||
{
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
BOOL isDir;
|
||||
|
||||
if (! ([fm fileExistsAtPath: path isDirectory: &isDir] && isDir == YES))
|
||||
return;
|
||||
|
||||
NSDate *dateLastCached;
|
||||
NSDate *modificationDate;
|
||||
|
||||
dateLastCached = [cachedDirs objectForKey: path];
|
||||
if (dateLastCached == nil)
|
||||
dateLastCached = [NSDate distantPast];
|
||||
|
||||
if (mergeCache)
|
||||
modificationDate = [[fm fileAttributesAtPath: path
|
||||
traverseLink: YES] fileModificationDate];
|
||||
else
|
||||
modificationDate = [NSDate distantFuture];
|
||||
|
||||
int i;
|
||||
NSArray *ls = [fm directoryContentsAtPath: path];
|
||||
int count = [ls count];
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
NSString *fontPath =
|
||||
[path stringByAppendingPathComponent: [ls objectAtIndex: i]];
|
||||
|
||||
if ([fm fileExistsAtPath: fontPath isDirectory: &isDir] && isDir == YES)
|
||||
{
|
||||
if ([[fontPath pathExtension] isEqual: @"nfont"])
|
||||
{
|
||||
if ([dateLastCached earlierDate: bundleModificationDate(fontPath)] ==
|
||||
dateLastCached)
|
||||
{
|
||||
cacheNFontBundle(fontPath, fontCache, mergeCache);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheFolder(fontPath,
|
||||
fontCache,
|
||||
cachedDirs,
|
||||
mergeCache,
|
||||
library);
|
||||
}
|
||||
}
|
||||
else if ([dateLastCached earlierDate: modificationDate] ==
|
||||
dateLastCached)
|
||||
{
|
||||
cacheFont(fontPath, fontCache, mergeCache, library);
|
||||
}
|
||||
}
|
||||
|
||||
[cachedDirs setObject: [NSDate date] forKey: path];
|
||||
}
|
||||
|
||||
- (void) enumerateFontsAndFamilies
|
||||
{
|
||||
int i;
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableArray *fontCache;
|
||||
NSMutableDictionary *cachedDirs;
|
||||
BOOL mergeCache = YES;
|
||||
|
||||
/*
|
||||
* Open font cache:
|
||||
*/
|
||||
|
||||
NSString *cachePath =
|
||||
[[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
||||
NSUserDomainMask,
|
||||
YES) objectAtIndex: 0]
|
||||
stringByAppendingPathComponent: @"FontInfo/FontCache.plist"];
|
||||
|
||||
switch ([fm fileExistsAtPath: cachePath])
|
||||
{
|
||||
case YES:
|
||||
if (!(fontCache = [NSMutableArray arrayWithContentsOfFile: cachePath]))
|
||||
{
|
||||
NSLog(@"Couldn't open font cache: %@", cachePath);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fontCache = [[NSMutableArray alloc] init];
|
||||
mergeCache = NO;
|
||||
}
|
||||
|
||||
NSString *dirsPath =
|
||||
[[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
||||
NSUserDomainMask,
|
||||
YES) objectAtIndex: 0]
|
||||
stringByAppendingPathComponent: @"FontInfo/CachedDirs.plist"];
|
||||
|
||||
switch ([fm fileExistsAtPath: cachePath])
|
||||
{
|
||||
case YES:
|
||||
if ((cachedDirs =
|
||||
[NSMutableDictionary dictionaryWithContentsOfFile: dirsPath]))
|
||||
break;
|
||||
default:
|
||||
cachedDirs = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure all fonts are cached:
|
||||
*/
|
||||
|
||||
NSMutableArray *searchPaths = [[NSMutableArray alloc] initWithArray:
|
||||
NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
||||
NSAllDomainsMask,
|
||||
YES)];
|
||||
|
||||
int count = [searchPaths count];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
NSString *path = [[searchPaths objectAtIndex: i]
|
||||
stringByAppendingPathComponent: @"Fonts"];
|
||||
|
||||
[searchPaths replaceObjectAtIndex: i withObject: path];
|
||||
}
|
||||
|
||||
if ([ud objectForKey: @"GSAdditionalFontPaths"] != nil)
|
||||
[searchPaths addObjectsFromArray:
|
||||
[ud objectForKey: @"GSAdditionalFontPaths"]];
|
||||
|
||||
FT_Library library;
|
||||
FT_Init_FreeType(&library);
|
||||
|
||||
count = [searchPaths count];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
|
||||
cacheFolder([searchPaths objectAtIndex: i],
|
||||
fontCache,
|
||||
cachedDirs,
|
||||
mergeCache,
|
||||
library);
|
||||
}
|
||||
|
||||
FT_Done_FreeType(library);
|
||||
|
||||
/*
|
||||
* Enumerate fonts and families:
|
||||
*/
|
||||
|
||||
NSMutableDictionary *mutableAllFonts = [[NSMutableDictionary alloc] init];
|
||||
NSMutableArray *mutableAllFontNames = [[NSMutableArray alloc] init];
|
||||
NSMutableDictionary *mutableAllFontFamilies =
|
||||
[[NSMutableDictionary alloc] init];
|
||||
|
||||
count = [fontCache count];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
NSDictionary *face = [fontCache objectAtIndex: i];
|
||||
CairoFaceInfo *faceInfo = [CairoFaceInfo alloc];
|
||||
|
||||
NSString *family;
|
||||
NSString *postScriptName;
|
||||
NSString *name;
|
||||
NSString *fullName;
|
||||
NSArray *files;
|
||||
int weight;
|
||||
int index;
|
||||
NSFontTraitMask traits;
|
||||
float italicAngle;
|
||||
|
||||
if ([face objectForKey: @"Family"] == nil ||
|
||||
[face objectForKey: @"PostScriptName"] == nil ||
|
||||
[face objectForKey: @"Name"] == nil ||
|
||||
[face objectForKey: @"Files"] == nil ||
|
||||
[[face objectForKey: @"Files"] count] < 1)
|
||||
continue;
|
||||
|
||||
family = [face objectForKey: @"Family"];
|
||||
postScriptName = [face objectForKey: @"PostScriptName"];
|
||||
name = [face objectForKey: @"Name"];
|
||||
files = [face objectForKey: @"Files"];
|
||||
|
||||
if ([mutableAllFontNames containsObject: postScriptName])
|
||||
continue;
|
||||
else
|
||||
[mutableAllFontNames addObject: postScriptName];
|
||||
|
||||
if ([face objectForKey: @"Index"] == nil)
|
||||
index = 0;
|
||||
else
|
||||
index = [[face objectForKey: @"Index"] intValue];
|
||||
|
||||
if ([face objectForKey: @"FullName"] == nil)
|
||||
fullName = [NSString stringWithFormat: @"%@ %@", family, name];
|
||||
else
|
||||
fullName = [face objectForKey: @"FullName"];
|
||||
|
||||
if ([face objectForKey: @"Weight"] == nil)
|
||||
weight = 5;
|
||||
else
|
||||
weight = [[face objectForKey: @"Weight"] intValue];
|
||||
|
||||
if ([face objectForKey: @"Traits"] == nil)
|
||||
traits = 0;
|
||||
else
|
||||
traits = [[face objectForKey: @"Traits"] unsignedIntValue];
|
||||
|
||||
if ([face objectForKey: @"ItalicAngle"] == nil)
|
||||
italicAngle = 0.0;
|
||||
else
|
||||
italicAngle = [[face objectForKey: @"ItalicAngle"] floatValue];
|
||||
|
||||
faceInfo = [faceInfo initWithfamilyName: family
|
||||
fullName: fullName
|
||||
weight: weight
|
||||
italicAngle: italicAngle
|
||||
traits: traits
|
||||
files: files
|
||||
index: index];
|
||||
|
||||
[mutableAllFonts setObject: faceInfo forKey: postScriptName];
|
||||
|
||||
NSArray *familyFace = [[NSArray alloc]
|
||||
initWithObjects: postScriptName,
|
||||
name,
|
||||
[NSNumber numberWithInt: weight],
|
||||
[NSNumber numberWithUnsignedInt: traits], nil];
|
||||
|
||||
NSMutableArray *familyFaceArray =
|
||||
[mutableAllFontFamilies objectForKey: family];
|
||||
|
||||
if (familyFaceArray == nil)
|
||||
{
|
||||
familyFaceArray = [[NSMutableArray alloc] init];
|
||||
[mutableAllFontFamilies setObject: familyFaceArray forKey: family];
|
||||
}
|
||||
|
||||
[familyFaceArray addObject: familyFace];
|
||||
}
|
||||
|
||||
allFontNames = mutableAllFontNames;
|
||||
allFontFamilies = mutableAllFontFamilies;
|
||||
__allFonts = mutableAllFonts;
|
||||
|
||||
/*
|
||||
* Write cache back to file:
|
||||
*/
|
||||
|
||||
NSString * fontInfoDir = [cachePath stringByDeletingLastPathComponent];
|
||||
|
||||
if (! [fm fileExistsAtPath: fontInfoDir])
|
||||
{
|
||||
[fm createDirectoryAtPath: fontInfoDir attributes: nil];
|
||||
}
|
||||
|
||||
if ([fontCache writeToFile: cachePath atomically: YES] == NO)
|
||||
{
|
||||
NSLog(@"Couldn't write font cache.");
|
||||
}
|
||||
|
||||
if ([cachedDirs writeToFile: dirsPath atomically: YES] == NO)
|
||||
{
|
||||
NSLog(@"Couldn't write cached directory info.");
|
||||
}
|
||||
}
|
||||
|
||||
+ (CairoFaceInfo *) fontWithName: (NSString *) name
|
||||
{
|
||||
CairoFaceInfo *face;
|
||||
|
@ -62,149 +685,12 @@ NSMutableDictionary * __allFonts;
|
|||
return face;
|
||||
}
|
||||
|
||||
// Make a GNUStep style font descriptor from a FcPattern
|
||||
static NSArray *faFromFc(FcPattern *pat)
|
||||
{
|
||||
int weight, slant, spacing, nsweight;
|
||||
unsigned int nstraits = 0;
|
||||
char *family;
|
||||
NSMutableString *name, *style;
|
||||
|
||||
if (FcPatternGetInteger(pat, FC_WEIGHT, 0, &weight) != FcResultMatch
|
||||
|| FcPatternGetInteger(pat, FC_SLANT, 0, &slant) != FcResultMatch
|
||||
|| FcPatternGetString(pat, FC_FAMILY, 0, (FcChar8 **)&family)
|
||||
!= FcResultMatch)
|
||||
return nil;
|
||||
|
||||
if (FcPatternGetInteger(pat, FC_SPACING, 0, &spacing) == FcResultMatch)
|
||||
if (spacing==FC_MONO || spacing==FC_CHARCELL)
|
||||
nstraits |= NSFixedPitchFontMask;
|
||||
|
||||
name = [NSMutableString stringWithCapacity: 100];
|
||||
style = [NSMutableString stringWithCapacity: 100];
|
||||
[name appendString: [NSString stringWithUTF8String: family]];
|
||||
|
||||
switch (weight)
|
||||
{
|
||||
case FC_WEIGHT_LIGHT:
|
||||
[style appendString: @"Light"];
|
||||
nsweight = 3;
|
||||
break;
|
||||
case FC_WEIGHT_MEDIUM:
|
||||
nsweight = 6;
|
||||
break;
|
||||
case FC_WEIGHT_DEMIBOLD:
|
||||
[style appendString: @"Demibold"];
|
||||
nsweight = 7;
|
||||
break;
|
||||
case FC_WEIGHT_BOLD:
|
||||
[style appendString: @"Bold"];
|
||||
nsweight = 9;
|
||||
nstraits |= NSBoldFontMask;
|
||||
break;
|
||||
case FC_WEIGHT_BLACK:
|
||||
[style appendString: @"Black"];
|
||||
nsweight = 12;
|
||||
nstraits |= NSBoldFontMask;
|
||||
break;
|
||||
default:
|
||||
nsweight = 6;
|
||||
}
|
||||
|
||||
switch (slant)
|
||||
{
|
||||
case FC_SLANT_ROMAN:
|
||||
break;
|
||||
case FC_SLANT_ITALIC:
|
||||
[style appendString: @"Italic"];
|
||||
nstraits |= NSItalicFontMask;
|
||||
break;
|
||||
case FC_SLANT_OBLIQUE:
|
||||
[style appendString: @"Oblique"];
|
||||
nstraits |= NSItalicFontMask;
|
||||
break;
|
||||
}
|
||||
|
||||
if ([style length] > 0)
|
||||
{
|
||||
[name appendString: @"-"];
|
||||
[name appendString: style];
|
||||
}
|
||||
else
|
||||
{
|
||||
[style appendString: @"Roman"];
|
||||
}
|
||||
|
||||
return [NSArray arrayWithObjects: name,
|
||||
style,
|
||||
[NSNumber numberWithInt: nsweight],
|
||||
[NSNumber numberWithUnsignedInt: nstraits],
|
||||
nil];
|
||||
}
|
||||
|
||||
- (void) enumerateFontsAndFamilies
|
||||
{
|
||||
int i;
|
||||
NSMutableDictionary *fcxft_allFontFamilies = [NSMutableDictionary new];
|
||||
NSMutableDictionary *fcxft_allFonts = [NSMutableDictionary new];
|
||||
NSMutableArray *fcxft_allFontNames = [NSMutableArray new];
|
||||
|
||||
FcPattern *pat = FcPatternCreate();
|
||||
FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, FC_SLANT, FC_WEIGHT, NULL);
|
||||
FcFontSet *fs = FcFontList(NULL, pat, os);
|
||||
|
||||
FcPatternDestroy(pat);
|
||||
FcObjectSetDestroy(os);
|
||||
|
||||
for (i = 0; i < fs->nfont; i++)
|
||||
{
|
||||
char *family;
|
||||
|
||||
if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, (FcChar8 **)&family)
|
||||
== FcResultMatch)
|
||||
{
|
||||
NSArray *fontArray;
|
||||
|
||||
if ((fontArray = faFromFc(fs->fonts[i])))
|
||||
{
|
||||
NSString *familyString;
|
||||
NSMutableArray *familyArray;
|
||||
CairoFaceInfo *aFont;
|
||||
NSString *name = [fontArray objectAtIndex: 0];
|
||||
|
||||
familyString = [NSString stringWithUTF8String: family];
|
||||
familyArray = [fcxft_allFontFamilies objectForKey: familyString];
|
||||
if (familyArray == nil)
|
||||
{
|
||||
NSDebugLog(@"Found font family %@", familyString);
|
||||
familyArray = [[NSMutableArray alloc] init];
|
||||
[fcxft_allFontFamilies setObject: familyArray
|
||||
forKey: familyString];
|
||||
RELEASE(familyArray);
|
||||
}
|
||||
NSDebugLog(@"fc enumerator: adding font: %@", name);
|
||||
[familyArray addObject: fontArray];
|
||||
[fcxft_allFontNames addObject: name];
|
||||
aFont = [[CairoFaceInfo alloc] initWithfamilyName: familyString
|
||||
weight: [[fontArray objectAtIndex: 2] intValue]
|
||||
traits: [[fontArray objectAtIndex: 3] unsignedIntValue]
|
||||
pattern: fs->fonts[i]];
|
||||
[fcxft_allFonts setObject: aFont forKey: name];
|
||||
RELEASE(aFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
FcFontSetDestroy (fs);
|
||||
|
||||
allFontNames = fcxft_allFontNames;
|
||||
allFontFamilies = fcxft_allFontFamilies;
|
||||
__allFonts = fcxft_allFonts;
|
||||
}
|
||||
|
||||
- (NSString *) defaultSystemFontName
|
||||
{
|
||||
if ([allFontNames containsObject: @"Bitstream Vera Sans"])
|
||||
return @"Bitstream Vera Sans";
|
||||
if ([allFontNames containsObject: @"BitstreamVeraSans-Roman"])
|
||||
return @"BitstreamVeraSans-Roman";
|
||||
if ([allFontNames containsObject: @"FreeSans"])
|
||||
return @"FreeSans";
|
||||
return @"Helvetica";
|
||||
|
@ -214,6 +700,8 @@ static NSArray *faFromFc(FcPattern *pat)
|
|||
{
|
||||
if ([allFontNames containsObject: @"Bitstream Vera Sans-Bold"])
|
||||
return @"Bitstream Vera Sans-Bold";
|
||||
if ([allFontNames containsObject: @"BitstreamVeraSans-Bold"])
|
||||
return @"BitstreamVeraSans-Bold";
|
||||
if ([allFontNames containsObject: @"FreeSans-Bold"])
|
||||
return @"FreeSans-Bold";
|
||||
return @"Helvetica-Bold";
|
||||
|
@ -223,6 +711,8 @@ static NSArray *faFromFc(FcPattern *pat)
|
|||
{
|
||||
if ([allFontNames containsObject: @"Bitstream Vera Sans Mono"])
|
||||
return @"Bitstream Vera Sans Mono";
|
||||
if ([allFontNames containsObject: @"BitstreamVeraSansMono-Roman"])
|
||||
return @"BitstreamVeraSansMono-Roman";
|
||||
if ([allFontNames containsObject: @"FreeMono"])
|
||||
return @"FreeMono";
|
||||
return @"Courier";
|
||||
|
|
|
@ -75,13 +75,18 @@
|
|||
[self setCacheSize: [_faceInfo cacheSize]];
|
||||
|
||||
/* setting GSFontInfo:
|
||||
* weight, traits, familyName,
|
||||
* weight, italicAngle, traits, familyName, fullName
|
||||
* mostCompatibleStringEncoding, encodingScheme,
|
||||
*/
|
||||
|
||||
weight = [_faceInfo weight];
|
||||
italicAngle = [_faceInfo italicAngle];
|
||||
traits = [_faceInfo traits];
|
||||
familyName = [[_faceInfo familyName] copy];
|
||||
/* FIXME: GSFontInfo doesn't have full name yet.
|
||||
* NSfont also needs to be changed.
|
||||
* fullName = [[_faceInfo fullName] copy];
|
||||
*/
|
||||
mostCompatibleStringEncoding = NSUTF8StringEncoding;
|
||||
encodingScheme = @"iso10646-1";
|
||||
|
||||
|
|
Loading…
Reference in a new issue