/* 
 NSFreeTypeFont.m
 
 FreeType Wrapper
 
 Copyright (C) 1998 Free Software Foundation, Inc.
 
 Author:	H. N. Schaller <hns@computer.org>
 Date:		Jun 2007 - completely reworked

 Useful Manuals:
	http://tronche.com/gui/x/xlib											Xlib - basic X11 calls
    http://freetype.sourceforge.net/freetype2/docs/reference/ft2-toc.html	libFreetype2 - API
	http://freetype.sourceforge.net/freetype2/docs/tutorial/step1.html		a tutorial
	http://netmirror.org/mirror/xfree86.org/4.4.0/doc/HTML/Xft.3.html		Xft - freetype glue
	http://netmirror.org/mirror/xfree86.org/4.4.0/doc/HTML/Xrandr.3.html	XResize - rotate extension
	http://netmirror.org/mirror/xfree86.org/4.4.0/doc/HTML/Xrender.3.html	XRender - antialiased, alpha, subpixel rendering
 
 This file is part of the mySTEP Library and is provided
 under the terms of the GNU Library General Public License.
 */ 

#if 1	// set to 0 to disable libfreetype references

#import "NSX11GraphicsContext.h"
#import "NSFreeTypeFont.h"

// load full headers (to expand @class forward references)

#import "NSAppKitPrivate.h"
#import "NSApplication.h"
#import "NSAttributedString.h"
#import "NSBezierPath.h"
#import "NSColor.h"
#import "NSCursor.h"
#import "NSFont.h"
#import "NSGraphics.h"
#import "NSGraphicsContext.h"
#import "NSImage.h"
#import "NSScreen.h"
#import "NSWindow.h"
#import "NSPasteboard.h"
#import "NSGlyphGenerator.h"

@interface NSGraphicsContext (NSFreeTypeFont)
- (void) _drawGlyphBitmap:(unsigned char *) buffer x:(int) x y:(int) y width:(unsigned) width height:(unsigned) height;
@end

@implementation _NSX11Font (NSFreeTypeFont)

static float scale;		// cache for screen scale
static float rscale;	// cache for 1/screen scale
static float rscale64;	// cache for 1/(64.0*screen scale)

#define Free2Pt(VAL) ((VAL)*rscale64)	// we mignt need to undo global screen scaling!

- (float) ascender;
{
//	FT_Face f=_faceStruct;
	if(!FT_IS_SCALABLE(_faceStruct))
		;	// error
	return Free2Pt(_faceStruct->size->metrics.ascender);
}

- (NSRect) boundingRectForFont;
{
	return NSMakeRect(Free2Pt(_faceStruct->bbox.xMin), Free2Pt(_faceStruct->bbox.yMin), Free2Pt(_faceStruct->bbox.xMax-_faceStruct->bbox.xMin), Free2Pt(_faceStruct->bbox.yMax-_faceStruct->bbox.yMin));
}

- (float) capHeight;
{
	FT_Load_Glyph(_faceStruct, FT_Get_Char_Index(_faceStruct, 'X'), FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM);
	return Free2Pt(_faceStruct->glyph->metrics.horiBearingY);
}

// FIXME: should this be stored in the font cache (?) as NSFontCharacterSetAttribute

- (NSCharacterSet *) coveredCharacterSet;
{
	NSMutableCharacterSet *cs=[[NSMutableCharacterSet new] autorelease];
	FT_ULong charcode;                                              
	FT_UInt gindex;                                                	
	charcode = FT_Get_First_Char(_faceStruct, &gindex);                   
	while(gindex != 0)                                            
		{
		[cs addCharactersInRange:NSMakeRange(charcode, 1)];
		charcode = FT_Get_Next_Char(_faceStruct, charcode, &gindex);        
		}
	return cs;
}

- (float) descender; { return Free2Pt(_faceStruct->size->metrics.descender); }

- (void) getAdvancements:(NSSizeArray) advancements
			   forGlyphs:(const NSGlyph *) glyphs
				   count:(unsigned) count;
{
	while(count-- > 0)
		{
		NSSize sz;
		FT_Load_Glyph(_faceStruct, *glyphs++, FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM);
		if(_renderingMode == NSFontAntialiasedIntegerAdvancementsRenderingMode)
			{ // a little faster but less accurate
			sz=NSMakeSize(_faceStruct->glyph->advance.x>>6, _faceStruct->glyph->advance.y>>6);
			}
		else
			{ // needs additional float operations per step
				// FIXME - appears to have both horiz&vert advancement
			sz=NSMakeSize(_faceStruct->glyph->linearHoriAdvance*(1.0/65536.0), 0* _faceStruct->glyph->linearVertAdvance*(1.0/65536.0));
			}
		*advancements++=sz;
		}
}

- (void) getAdvancements:(NSSizeArray) advancements
		 forPackedGlyphs:(const void *) glyphs
				   count:(unsigned) count; { NIMP; }

- (void) getBoundingRects:(NSRectArray) bounds
				forGlyphs:(const NSGlyph *) glyphs
					count:(unsigned) count;
{
	while(count-- > 0)
		{
		NSRect rect;
		FT_Load_Glyph(_faceStruct, *glyphs++, FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM);
		rect=NSMakeRect(Free2Pt(_faceStruct->glyph->metrics.horiBearingX), Free2Pt(_faceStruct->glyph->metrics.height-_faceStruct->glyph->metrics.horiBearingY),
						Free2Pt(_faceStruct->glyph->metrics.width), Free2Pt(_faceStruct->glyph->metrics.height));
		*bounds++=rect;
		}
}


- (NSGlyph) glyphWithName:(NSString *) name;
{
	FT_UInt glyph=FT_Get_Name_Index(_faceStruct, (FT_String *) [name cString]);
	if(glyph == 0)
		return NSNullGlyph;
	return glyph;
}

- (BOOL) isFixedPitch;	{ return FT_IS_FIXED_WIDTH(_faceStruct) != 0; }

- (float) italicAngle; { return 0.0; }	// FIXME

- (float) leading; { return Free2Pt(_faceStruct->size->metrics.height-(_faceStruct->size->metrics.ascender-_faceStruct->size->metrics.descender)); }

- (float) defaultLineHeightForFont; { return Free2Pt(_faceStruct->size->metrics.height); }

- (NSSize) maximumAdvancement; { return NSMakeSize(Free2Pt(_faceStruct->max_advance_width), Free2Pt(_faceStruct->max_advance_height)); }

- (NSStringEncoding) mostCompatibleStringEncoding;
{
	NSStringEncoding enc=NSASCIIStringEncoding;
	int i;
	for(i=0; i<_faceStruct->num_charmaps; i++)
		{
		switch(_faceStruct->charmaps[i]->encoding)
			{
			case FT_ENCODING_UNICODE:
				enc=NSUnicodeStringEncoding;
				break;
			case FT_ENCODING_APPLE_ROMAN:
				enc=NSMacOSRomanStringEncoding;
				break;
			default:
				break;
			}
		}
	return enc;
}

- (unsigned) numberOfGlyphs; { return _faceStruct->num_glyphs; }

- (float) underlinePosition; { return Free2Pt(_faceStruct->underline_position); }

- (float) underlineThickness; { return Free2Pt(_faceStruct->underline_thickness); }

- (float) xHeight;
{
	FT_Load_Glyph(_faceStruct, FT_Get_Char_Index(_faceStruct, 'x'), FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM);
	return Free2Pt(_faceStruct->glyph->metrics.horiBearingY);
}

- (id) _initWithDescriptor:(NSFontDescriptor *) desc
{
	if(scale == 0.0)
		{ // initialize cache
		scale=[[[[[NSScreen screens] objectAtIndex:0] deviceDescription] objectForKey:@"systemSpaceScaleFactor"] floatValue];
		rscale=1.0/scale;
		rscale64=rscale/64.0;
		}
	if((self=[super init]))
		{
		_renderingMode=NSFontAntialiasedRenderingMode;
		_descriptor=[desc retain];
		if(![self _face])
			{ // can't load backend info
#if 1
			NSLog(@"Can't find font with descriptor %@", desc);
#endif
			[self release];
			return nil;
			}
		}
	return self;
}

FT_Library _ftLibrary(void)
{
	FT_Error error;
	static FT_Library _freetypeLibrary;	// For multi-threaded applications each thread should have its own FT_Library object!
	if(!_freetypeLibrary)
		{
		if((error=FT_Init_FreeType(&_freetypeLibrary)))
			[NSException raise:NSGenericException format:@"Unable to initialize libFreetype"];
		}
	return _freetypeLibrary;
}

- (void) _clear;
{
	if(_faceStruct)
		{
		FT_Done_Face(_faceStruct);
		_backendPrivate=NULL;
		}
}

- (FT_Face) _face;
{ // get _face
	if(!_faceStruct)
		{ // not yet initialized
		NSDictionary *attribs=[_descriptor fontAttributes];
		if(attribs)
			{
			FT_Error error;
			FT_Long	faceIndex=[[attribs objectForKey:@"FaceNumber"] unsignedLongValue];
			NSString *fontFile=[attribs objectForKey:@"FilePath"];
			_backendPrivate=NULL;
			error=FT_New_Face(_ftLibrary(), [fontFile fileSystemRepresentation], faceIndex, (FT_Face *) &_backendPrivate);
			if(!error)
				{ // scale points to screen size
				FT_Error error;
				error=FT_Set_Pixel_Sizes(_faceStruct, 0, (int) (scale*[_descriptor pointSize]));
				if(!error)
					return _faceStruct;
				}
			NSLog(@"*** Internal font loading error: %@", fontFile);
			}
		}
	return _faceStruct;
}

- (void) _finalize
{ // called when deallocating the X11Font
	if(_faceStruct)
		FT_Done_Face(_faceStruct);
}

- (NSGlyph) _glyphForCharacter:(unichar) c;
	// FIXME - this should be moved to NSGlyphGenerator!
{
	return FT_Get_Char_Index(_faceStruct, c);
}

- (float) _widthOfAntialisedString:(NSString *) string;
{ // deprecated...
	FT_Matrix matrix = { 1<<16, 0, 0, 1<<16 };	// identity matrix
	FT_Vector delta = { 0, 0 };
	FT_GlyphSlot slot = _faceStruct->glyph;
	unsigned long i, cnt=[string length];
	// we could sum up the integer widths/heights and convert to float only once
	for(i = 0; i < cnt; i++)
		{ // load glyphs but don't transform
		FT_Error error;
		FT_Set_Transform(_faceStruct,			// handle to face object
						 &matrix,				// pointer to 2x2 matrix
						 &delta);				// pointer to 2d vector
		error = FT_Load_Char(_faceStruct, [string characterAtIndex:i], FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM);
		if(error)
			continue;
		delta.x += slot->advance.x;
//		delta.y += slot->advance.y;	// returns bad value here and we can't handle vertical rendering anyway
		}
	return Free2Pt(delta.x);
}

// this is used for freetype with our non-XRender based drawing

- (void) _drawAntialisedGlyphs:(NSGlyph *) glyphs count:(unsigned) cnt inContext:(NSGraphicsContext *) ctxt matrix:(NSAffineTransform *) ctm;
{ // render the string
	FT_GlyphSlot slot = _faceStruct->glyph;
	NSPoint pen = [ctm transformPoint:NSZeroPoint];
	FT_Matrix matrix = { 1<<16, 0, 0, 1<<16 };	// identity matrix
	FT_Vector delta;
	NSAffineTransform *t=[_descriptor matrix];
	// catenate Font matrix (if available)
	// with text matrix
	// with CTM
	// remove scaling (i.e. make it a non-scaling transformation matrix) - scale = sqrt(m11*m11+m22*m22)
	if(t)
		{ // we have a font with an explicit text transform
		NSAffineTransformStruct m=[t transformStruct];		
		// divide by [_descriptor pointSize] so that a rotation/shearing part remains
		matrix = (FT_Matrix) { m.m11*(1<<16), m.m12*(1<<16), m.m21*(1<<16), m.m22*(1<<16) };
		delta = (FT_Vector) { m.tX*64, m.tY*64 };
		}
	else
		{ // translate only
		delta.x=(int)(64*pen.x);
		delta.y=32-(int)(64*pen.y);
		}
	while(cnt-- > 0)
		{ // render glyphs
		FT_Error error;
		FT_Set_Transform(_faceStruct,			// handle to face object
						 &matrix,				// pointer to 2x2 matrix
						 &delta);				// pointer to 2d vector
		error = FT_Load_Glyph(_faceStruct, *glyphs++, FT_LOAD_RENDER);
		if(error)
			continue;
		// x,y is the top/left position in X11 coordinates, i.e. counted from top/left of screen
		[ctxt _drawGlyphBitmap:slot->bitmap.buffer x:slot->bitmap_left y:-slot->bitmap_top width:slot->bitmap.width height:slot->bitmap.rows];
		delta.x += slot->advance.x;
		delta.y += slot->advance.y;
		}
}

// this is used when using the XRender GlyphSets

- (void) _defineGlyphs;
{ // and add to GlyphSet
	FT_ULong charcode;
	FT_UInt gindex;
	FT_GlyphSlot slot = _faceStruct->glyph;
	FT_Matrix matrix = { 1<<16, 0, 0, 1<<16 };	// identity matrix
	FT_Vector delta = { 0, 0 };
	NSAffineTransform *t=[_descriptor matrix];
#if 1
	NSLog(@"_defineGlyphs %@", self);
#endif
	if(t)
		{ // we have a font with an explicit text transform
			NSAffineTransformStruct m=[t transformStruct];		
			matrix = (FT_Matrix) { m.m11*(1<<16), m.m12*(1<<16), m.m21*(1<<16), m.m22*(1<<16) };
			delta = (FT_Vector) { m.tX*64, m.tY*64 };
		}
	FT_Set_Transform(_faceStruct,			// handle to face object
					 &matrix,				// pointer to 2x2 matrix
					 &delta);				// pointer to 2d vector
	charcode=FT_Get_First_Char(_faceStruct, &gindex);
	while(gindex != 0)
		{ // loop through all glyphs
			FT_Error error;
			NSLog(@"char=%04x glyph=%d", charcode, gindex);
			error = FT_Load_Glyph(_faceStruct, gindex, FT_LOAD_RENDER);
			if(!error && slot->bitmap.width > 0 && slot->bitmap.rows > 0)
				[self _addGlyph:(NSGlyph) gindex bitmap:(char *) slot->bitmap.buffer x:slot->bitmap_left y:slot->bitmap_top width:slot->bitmap.width height:slot->bitmap.rows];
			charcode=FT_Get_Next_Char(_faceStruct, charcode, &gindex);
		}
}

// this is used when we have our own glyph cache

- (_CachedGlyph) _defineGlyph:(NSGlyph) glyph;
{ // and add to GlyphSet
	FT_Error error;
	FT_GlyphSlot slot = _faceStruct->glyph;
	FT_Matrix matrix = { 1<<16, 0, 0, 1<<16 };	// identity matrix
	FT_Vector delta = { 0, 0 };
	NSAffineTransform *t=[_descriptor matrix];
#if 0
	NSLog(@"_defineGlyph %d %p", glyph, self);
#endif
	if(t)
			{ // we have a font with an explicit text transform
				NSAffineTransformStruct m=[t transformStruct];		
				matrix = (FT_Matrix) { m.m11*(1<<16), m.m12*(1<<16), m.m21*(1<<16), m.m22*(1<<16) };
				delta = (FT_Vector) { m.tX*64, m.tY*64 };
			}
	FT_Set_Transform(_faceStruct,			// handle to face object
									 &matrix,				// pointer to 2x2 matrix
									 &delta);				// pointer to 2d vector
	error = FT_Load_Glyph(_faceStruct, glyph, FT_LOAD_RENDER);
	if(!error && slot->bitmap.width > 0 && slot->bitmap.rows > 0)
			{
				_CachedGlyph g=(_CachedGlyph) objc_malloc(sizeof(*g));	// create new record
				[self _addGlyphToCache:g bitmap:(char *) slot->bitmap.buffer x:slot->bitmap_left y:slot->bitmap_top width:slot->bitmap.width height:slot->bitmap.rows];	// convert into Picture
			return g;
			}
	return NULL;
}

@end

@implementation NSGlyphGenerator (NSFreeTypeFont)

- (void) generateGlyphsForGlyphStorage:(id <NSGlyphStorage>) storage
			 desiredNumberOfCharacters:(unsigned int) num
							glyphIndex:(unsigned int *) gidx
						characterIndex:(unsigned int *) cidx
{
	NSAttributedString *astr=[storage attributedString];	// get string to layout
	NSString *str=[astr string];
	unsigned int options=[storage layoutOptions];	 // NSShowControlGlyphs, NSShowInvisibleGlyphs, NSWantsBidiLevels
	NSGlyph previous=0;
	BOOL usekerning=YES;	// ask storage?
	while(num > 0)
		{
		
		// FIXME: handle invisible characters, make page breaks etc. optionally visible, handle multi-character glyphs (ligatures), multi-glyph characters etc.
		// convert unicode to glyph encoding
		
		// loop through characters
		// switch fonts as necessary
		// add line breaks (?)
		// convert character to glyph encoding

		NSGlyph glyph;
		int gnum=1;
		unichar c=[str characterAtIndex:*cidx];
		NSDictionary *attribs=[astr attributesAtIndex:*cidx effectiveRange:NULL];
		NSFont *font=[attribs objectForKey:@"Font"];
		FT_Face face=[(_NSX11Font *) font _face];
		switch(c)
			{
			// handle special characters like \n \t and textattachments depending on options
			default:
				glyph=FT_Get_Char_Index(face, c);
			}

		// generate position information
		if(usekerning && previous && glyph)
			{ // handle kerning
			FT_Vector delta;
			FT_Get_Kerning(face, previous, glyph, FT_KERNING_DEFAULT, &delta);
//			pen_x += Free2Pt(delta.x);
//			pen_y += Free2Pt(delta.y);
			previous=glyph;
			}
		[storage insertGlyphs:&glyph length:gnum forStartingGlyphAtIndex:*gidx characterIndex:*cidx];
//		[storage setIntAttribute:124 value:4321 forGlyphAtIndex:*gidx];
//		store glyph positions
		*gidx+=gnum;
		*cidx++;
		num--;
		}
}

@end

@implementation NSFontDescriptor (NSFreeTypeFont)	// the NSFontDescriptor can cache a libfreetype FT_Face structure

#define USE_SQLITE 0

#if USE_SQLITE	// sqlite based font cache - overwrites default implementation

#define FONT_CACHE	[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches/com.quantum-step.mySTEP.NSFonts.sqlite"]

+ (NSArray *) _matchingFontDescriptorsWithAttributes:(NSDictionary *) attributes mandatoryKeys:(NSSet *) keys limit:(unsigned) limit;
{ // this is the core font search engine that knows about font directories
	NSString *query=@"SELECT * FROM fonts";
	NSString *delim=@"WHERE";
	NSArray *keylist=nil;	// nur die die gespeichert werden!
	NSEnumerator *e=[keys objectEnumerator];
	NSString *key;
	while((key=[e nextObject]) && [keylist containsObject:key])
		query=[NSString stringWithFormat:@"%@ %@ %@='%@'", query, delim, key, [_attributes objectForKey:key]], delim=@"AND";
	if(limit < 99999)
		query=[NSString stringWithFormat:@"%@ LIMIT %u", query, limit];
	NSLog(@"query=%@", query);
	abort();
	return nil;
}

+ (NSDictionary *) _fonts;
{
	return NIMP;
}

+ (void) _writeFonts;
{
	return;
}

+ (void) _addFontWithAttributes:(NSDictionary *) record;
{ // add a system record that helps to find the font file
	NSEnumerator *e=[record keyEnumerator];
	NSString *key;
	// create table fonts (Name text,Family text,Face text,PostscriptName text, Traits integer, FaceNumber integer,FilePath text);
	const char *path=[FONT_CACHE fileSystemRepresentation];
	FILE *f=fopen(path, "a");
	char c;
	fprintf(f, "insert into fonts ");
	c='(';
	while((key=[e nextObject]))
		fprintf(f, "%c%s", c, [key cString]), c=',';
	fprintf(f, ") values ");
	c='(';
	e=[record keyEnumerator];
	while((key=[e nextObject]))
		fprintf(f, "%c'%s'", c, [[[record objectForKey:key] description] UTF8String]), c=',';
	fprintf(f, ");\n");
	fclose(f);
}
#endif

+ (NSString *) _loadFontsFromFile:(NSString *) path;
{ // try to load to cache - ignore if we can't really load
	FT_Long	faceIndex;
	FT_Long numFaces=10;
	FT_Face face;
	NSString *family=nil;
#if 0
	NSLog(@"_loadFontsFromFile:%@", path);
#endif
	for(faceIndex=0; faceIndex < numFaces; faceIndex++)
		{ // loop until we can't read a given face
		FT_Error error;
		NSMutableDictionary *fontRecord;
		NSString *postscriptName;	// assuming that the name is the same for all faces...
		NSString *style;
		NSString *name;
		NSFontTraitMask traits=0;
		int cnt;
		unsigned long lweight;
		float weight=0.0;
		const char *psname;
#if 0
		NSLog(@"try face #%lu num faces=%lu", faceIndex, numFaces);
#endif
		error=FT_New_Face(_ftLibrary(), [path fileSystemRepresentation], faceIndex, &face);	// try to load first face
		if(error == FT_Err_Unknown_File_Format)
			{
			NSLog(@"Invalid font file format: %@", path);
			return nil;
			}
		if(error)
			{
			NSLog(@"Unable to load font file %@ (error=%d)", path, error);
			return nil;	// any error
			}
#if 0
		NSLog(@"  -> num faces=%lu", face->num_faces);
#endif
		numFaces=face->num_faces;
		psname=FT_Get_Postscript_Name(face);
		if(!psname)
			continue;	// we can handle fonts with postscript names only
		if(!FT_IS_SCALABLE(face))
			continue;	// must be scalable - FIXME: we could derive a NSFontSizeAttribute
		family=[NSString stringWithCString:face->family_name];
		if(!face->style_name || strcmp(face->style_name, "Regular") == 0)
			{ // style name N/A or "Regular"
			style=@"";
			name=family;
			}
		else
			{ // explicit style name available
			style=[NSString stringWithCString:face->style_name];
			name=[NSString stringWithFormat:@"%@-%@", family, style];	// build display name
			}
		if(face->style_flags&FT_STYLE_FLAG_ITALIC)
			traits |= NSItalicFontMask;
//		else
//			traits |= NSUnitalicFontMask;
		if(face->style_flags&FT_STYLE_FLAG_BOLD)
			traits |= NSBoldFontMask;
//		else
//			traits |= NSUnboldFontMask;
		// nonstandardcharset traits
		// narrowfont
		// expanded
		// condensed
		// smallcaps
		// posterfont
		// compressed
		if(FT_IS_FIXED_WIDTH(face))
			traits |= NSFixedPitchFontMask;
		FT_Set_Pixel_Sizes(face, 0, 24);	// render approx. 24x24 pixels
		FT_Load_Glyph(face, FT_Get_Char_Index(face, 'x'), FT_LOAD_DEFAULT);	// draw a representative character
		cnt=face->glyph->bitmap.width*face->glyph->bitmap.rows;
		if(cnt)
			{
			lweight=0;
			while(cnt-- > 0)
				lweight+=face->glyph->bitmap.buffer[cnt];	// sum up all shaded values
			weight=(float)lweight/(255*face->glyph->bitmap.width*face->glyph->bitmap.rows);		// proportion of black and white pixels - this has to be scaled through all faces!
			}
		else
			weight=0.0;
#if 0
		NSLog(@"add font %lu [%lu] %@-%@ at %@", faceIndex, face->num_faces, family, style, path);
#endif
		postscriptName=[NSString stringWithCString:psname];
		fontRecord=[NSMutableDictionary dictionaryWithObjectsAndKeys:
			// official
			family, NSFontFamilyAttribute,
			style, NSFontFaceAttribute,
			postscriptName, NSFontNameAttribute,	// official name
			name, NSFontVisibleNameAttribute,	// display name
			[NSDictionary dictionaryWithObjectsAndKeys:
				[NSNumber numberWithUnsignedInt:traits], NSFontSymbolicTrait,
				[NSNumber numberWithFloat:weight], NSFontWeightTrait,	// -1.0 ... 1.0
				// NSFontSlantTrait
				// NSFontWidthTrait
				nil], NSFontTraitsAttribute,
			// internal
			path, @"FilePath",
			[NSNumber numberWithUnsignedLong:faceIndex], @"FaceNumber",
			nil];
		[NSFontDescriptor _addFontWithAttributes:fontRecord];		
		FT_Done_Face(face);
		}
	return family;
}

@end

@implementation NSBezierPath (Backend)

- (void) appendBezierPathWithGlyphs:(NSGlyph *)glyphs 
							  count:(int)count
							 inFont:(NSFont *)font
{
	FT_Face face=[(_NSX11Font *) font _face];
	NSFontRenderingMode renderingMode=[font renderingMode];
	FT_GlyphSlot slot = face->glyph;
	NSPoint pen = NSZeroPoint;
	NSAssert(face, @"can't convert font to Bezier Path");
	//	pen.y=[self ascender];	// one line down
	pen.y=(face->ascender+face->descender)>>6;
	while(count-- > 0)
		{ // render glyphs
		unsigned int i;
		FT_Error error = FT_Load_Glyph(face, *glyphs++, FT_LOAD_RENDER);	// CHECKME - do we really need to LOAD_RENDER?
		if(error)
			continue;
		for(i=0; i<slot->outline.n_contours; i++)
			{ // add contours to path
		/*
		 n_contours	
		 The number of contours in the outline.
		 
		 this is an inner loop!
		 
		 n_points	
		 The number of points in the outline.
		 
		 points	
		 A pointer to an array of ‘n_points’ FT_Vector elements, giving the outline's point coordinates.
		 
		 tags	
		 A pointer to an array of ‘n_points’ chars, giving each outline point's type. If bit 0 is unset, the point is ‘off’ the curve, i.e., a Bézier control point, while it is ‘on’ when set.
		 
		 Bit 1 is meaningful for ‘off’ points only. If set, it indicates a third-order Bézier arc control point; and a second-order control point if unset.
		 
		 switch(slot->outline->tags[i]&3)
		 {
			 case 0:	// second order control point
				 break;
			 case 1:	// line to
				 [self lineTo: ];
				 break;
			 case 2: // third order control point
				 
			 case 3:	// error
				 break;
		 }
		 
		 An array of ‘n_contours’ shorts, giving the end point of each contour within the outline. For example, the first contour is defined by the points ‘0’ to ‘contours[0]’, the second one is defined by the points ‘contours[0]+1’ to ‘contours[1]’, etc.
		 
		 
		 flags	
		 A set of bit flags used to characterize the outline and give hints to the scan-converter and hinter on how to convert/grid-fit it. See FT_OUTLINE_FLAGS.
		 
		 FT_OUTLINE_EVEN_ODD_FILL
		 By default, outlines are filled using the non-zero winding rule. If set to 1, the outline will be filled using the even-odd fill rule (only works with the smooth raster).
		 
		 
		 */
			}
		
		if(renderingMode == NSFontAntialiasedIntegerAdvancementsRenderingMode)
			{ // a little faster but less accurate
			pen.x += slot->advance.x>>6;
			pen.y += slot->advance.y>>6;
			}
		else
			{ // needs 4 additional float operations per step
			pen.x += slot->linearHoriAdvance*(1.0/65536);
			// not reliable	- use FT_HAS_VERTICAL()		pen.y += slot->linearVertAdvance*(1.0/65536);
			}
		[self closePath];	// ??? and start new path for next glyph or is a moveTo: the start indicator.
		}
#if 1
	NSLog(@"path=%@", self);
#endif
}

- (void) appendBezierPathWithPackedGlyphs:(const char *)packedGlyphs
{
	NIMP;
}

@end

#endif

// EOF