2002-08-20 16:36:09 +00:00
|
|
|
/*
|
2005-01-11 15:02:29 +00:00
|
|
|
Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
2002-08-27 10:11:20 +00:00
|
|
|
|
|
|
|
Author: Alexander Malmberg <alexander@malmberg.org>
|
2002-08-20 16:36:09 +00:00
|
|
|
|
|
|
|
This file is part of GNUstep.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-10-29 23:25:10 +00:00
|
|
|
modify it under the terms of the GNU Lesser General Public
|
2002-08-20 16:36:09 +00:00
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-10 04:12:46 +00:00
|
|
|
version 2 of the License, or (at your option) any later version.
|
2007-10-29 23:25:10 +00:00
|
|
|
|
2002-08-20 16:36:09 +00:00
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2007-10-29 23:25:10 +00:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
If not, see <http://www.gnu.org/licenses/> or write to the
|
|
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
2002-08-20 16:36:09 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
2010-03-26 07:51:34 +00:00
|
|
|
#import <Foundation/NSObject.h>
|
|
|
|
#import <Foundation/NSArray.h>
|
|
|
|
#import <Foundation/NSCharacterSet.h>
|
|
|
|
#import <Foundation/NSSet.h>
|
|
|
|
#import <Foundation/NSDictionary.h>
|
|
|
|
#import <Foundation/NSValue.h>
|
|
|
|
#import <Foundation/NSPathUtilities.h>
|
|
|
|
#import <Foundation/NSFileManager.h>
|
|
|
|
#import <Foundation/NSUserDefaults.h>
|
|
|
|
#import <Foundation/NSBundle.h>
|
|
|
|
#import <Foundation/NSDebug.h>
|
|
|
|
#import <GNUstepBase/Unicode.h>
|
|
|
|
|
|
|
|
#import <GNUstepGUI/GSFontInfo.h>
|
|
|
|
#import <AppKit/NSAffineTransform.h>
|
|
|
|
#import <AppKit/NSBezierPath.h>
|
|
|
|
|
|
|
|
#import "gsc/GSGState.h"
|
|
|
|
|
|
|
|
#import "ftfont.h"
|
|
|
|
#import "FTFontEnumerator.h"
|
2002-08-20 16:36:09 +00:00
|
|
|
|
|
|
|
#define DI (*di)
|
|
|
|
|
|
|
|
/** font handling interface **/
|
|
|
|
|
2020-01-17 15:23:07 +00:00
|
|
|
#include FT_FREETYPE_H
|
2002-08-20 16:36:09 +00:00
|
|
|
|
|
|
|
#include FT_CACHE_IMAGE_H
|
|
|
|
#include FT_CACHE_SMALL_BITMAPS_H
|
|
|
|
#include FT_CACHE_CHARMAP_H
|
|
|
|
|
|
|
|
#include FT_OUTLINE_H
|
|
|
|
|
|
|
|
|
2003-01-26 19:07:53 +00:00
|
|
|
/* TODO: finish screen font handling */
|
|
|
|
|
|
|
|
|
2002-08-27 09:59:22 +00:00
|
|
|
/*
|
|
|
|
from the back-art-subpixel-text defaults key
|
|
|
|
0: normal rendering
|
|
|
|
1: subpixel, rgb
|
|
|
|
2: subpixel, bgr
|
|
|
|
*/
|
|
|
|
static int subpixel_text;
|
|
|
|
|
|
|
|
@interface FTFontInfo_subpixel : FTFontInfo
|
|
|
|
@end
|
|
|
|
|
2002-08-20 16:36:09 +00:00
|
|
|
static FT_Library ft_library;
|
|
|
|
static FTC_Manager ftc_manager;
|
|
|
|
static FTC_ImageCache ftc_imagecache;
|
|
|
|
static FTC_SBitCache ftc_sbitcache;
|
|
|
|
static FTC_CMapCache ftc_cmapcache;
|
|
|
|
|
2009-01-13 00:34:14 +00:00
|
|
|
/*
|
|
|
|
* Helper method used inside of FTC_Manager to create an FT_FACE.
|
|
|
|
*/
|
|
|
|
static FT_Error ft_get_face(FTC_FaceID fid, FT_Library lib,
|
|
|
|
FT_Pointer data, FT_Face *pface)
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2002-08-21 13:02:26 +00:00
|
|
|
FT_Error err;
|
|
|
|
NSArray *rfi = (NSArray *)fid;
|
|
|
|
int i, c = [rfi count];
|
2009-01-13 00:34:14 +00:00
|
|
|
const char *face_name = [[rfi objectAtIndex: 0] fileSystemRepresentation];
|
2002-08-21 13:02:26 +00:00
|
|
|
|
2009-01-13 00:34:14 +00:00
|
|
|
NSDebugLLog(@"ftfont", @"ft_get_face: %@ '%s'", rfi, face_name);
|
|
|
|
err = FT_New_Face(lib, face_name, 0, pface);
|
2002-08-21 13:02:26 +00:00
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
NSLog(@"Error when loading '%@' (%08x)", [rfi objectAtIndex: 0], err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 1; i < c; i++)
|
|
|
|
{
|
2009-01-13 00:34:14 +00:00
|
|
|
face_name = [[rfi objectAtIndex: i] fileSystemRepresentation];
|
|
|
|
|
|
|
|
NSDebugLLog(@"ftfont", @" do '%s'", face_name);
|
|
|
|
err = FT_Attach_File(*pface, face_name);
|
2002-08-21 13:02:26 +00:00
|
|
|
if (err)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
NSLog(@"Error when loading '%@' (%08x)", [rfi objectAtIndex: i], err);
|
|
|
|
/* pretend it's alright */
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
}
|
2009-01-13 00:34:14 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
return 0;
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@implementation FTFontInfo
|
2008-04-04 22:07:03 +00:00
|
|
|
|
2006-11-19 11:08:09 +00:00
|
|
|
- (id) initWithFontName: (NSString *)name
|
2010-02-20 16:33:30 +00:00
|
|
|
matrix: (const CGFloat *)fmatrix
|
2008-04-04 22:07:03 +00:00
|
|
|
screenFont: (BOOL)p_screenFont
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
NSArray *rfi;
|
|
|
|
FTFaceInfo *font_entry;
|
|
|
|
FT_Error error;
|
2003-05-11 17:23:43 +00:00
|
|
|
|
2002-08-27 09:59:22 +00:00
|
|
|
if (subpixel_text)
|
|
|
|
{
|
|
|
|
[self release];
|
|
|
|
self = [FTFontInfo_subpixel alloc];
|
|
|
|
}
|
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
self = [super init];
|
2009-01-13 00:34:14 +00:00
|
|
|
if (!self)
|
|
|
|
return nil;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-06-29 15:36:28 +00:00
|
|
|
screenFont = p_screenFont;
|
2002-08-27 09:59:22 +00:00
|
|
|
|
2006-11-19 11:08:09 +00:00
|
|
|
NSDebugLLog(@"ftfont",
|
|
|
|
@"[%@ -initWithFontName: %@ matrix: (%g %g %g %g %g %g)] %i",
|
|
|
|
self, name,
|
|
|
|
fmatrix[0], fmatrix[1], fmatrix[2],
|
|
|
|
fmatrix[3], fmatrix[4], fmatrix[5],
|
|
|
|
p_screenFont);
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2007-08-22 11:54:13 +00:00
|
|
|
font_entry = [FTFontEnumerator fontWithName: name];
|
2002-08-21 13:02:26 +00:00
|
|
|
if (!font_entry)
|
|
|
|
{
|
2009-01-13 00:34:14 +00:00
|
|
|
RELEASE(self);
|
2003-07-02 15:38:35 +00:00
|
|
|
return nil;
|
2002-08-21 13:02:26 +00:00
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-09-14 11:03:41 +00:00
|
|
|
face_info = font_entry;
|
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
weight = font_entry->weight;
|
|
|
|
traits = font_entry->traits;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
fontName = [name copy];
|
2002-09-23 17:32:04 +00:00
|
|
|
familyName = [face_info->familyName copy];
|
2002-08-21 13:02:26 +00:00
|
|
|
memcpy(matrix, fmatrix, sizeof(matrix));
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
/* Using utf8 is a bit ugly, but it works. Besides, the bulk of the text
|
|
|
|
comes as glyphs anyway. */
|
2002-08-21 13:02:26 +00:00
|
|
|
mostCompatibleStringEncoding = NSUTF8StringEncoding;
|
|
|
|
encodingScheme = @"iso10646-1";
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-06-29 15:36:28 +00:00
|
|
|
if (screenFont)
|
|
|
|
{
|
2005-01-11 15:02:29 +00:00
|
|
|
/* Round up; makes the text more legible. */
|
2003-06-29 15:36:28 +00:00
|
|
|
matrix[0] = ceil(matrix[0]);
|
|
|
|
if (matrix[3] < 0.0)
|
2009-01-04 15:56:09 +00:00
|
|
|
matrix[3] = floor(matrix[3]);
|
2003-06-29 15:36:28 +00:00
|
|
|
else
|
2009-01-04 15:56:09 +00:00
|
|
|
matrix[3] = ceil(matrix[3]);
|
2003-06-29 15:36:28 +00:00
|
|
|
}
|
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
pix_width = fabs(matrix[0]);
|
|
|
|
pix_height = fabs(matrix[3]);
|
2002-09-26 14:08:55 +00:00
|
|
|
|
|
|
|
rfi = font_entry->files;
|
2006-11-19 11:08:09 +00:00
|
|
|
if (screenFont && font_entry->num_sizes && pix_width == pix_height)
|
2002-09-26 14:08:55 +00:00
|
|
|
{
|
|
|
|
int i;
|
2006-11-19 11:08:09 +00:00
|
|
|
|
2002-09-26 14:08:55 +00:00
|
|
|
for (i = 0; i < font_entry->num_sizes; i++)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
if (font_entry->sizes[i].pixel_size == pix_width)
|
|
|
|
{
|
|
|
|
rfi = font_entry->sizes[i].files;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2002-09-26 14:08:55 +00:00
|
|
|
}
|
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
faceId = (FTC_FaceID)rfi;
|
|
|
|
|
|
|
|
imageType.face_id = faceId;
|
|
|
|
imageType.width = pix_width;
|
|
|
|
imageType.height = pix_height;
|
|
|
|
/* TODO: Flags? */
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
scaler.face_id = faceId;
|
|
|
|
scaler.width = pix_width;
|
|
|
|
scaler.height = pix_height;
|
|
|
|
scaler.pixel = 1;
|
|
|
|
|
2007-01-31 15:52:53 +00:00
|
|
|
if ((error = FTC_Manager_LookupSize(ftc_manager, &scaler, &ft_size)))
|
2002-08-21 13:02:26 +00:00
|
|
|
{
|
2006-11-19 11:08:09 +00:00
|
|
|
NSLog(@"FTC_Manager_LookupSize() failed for '%@', error %08x!",
|
2008-04-04 22:07:03 +00:00
|
|
|
name, error);
|
2009-01-13 00:34:14 +00:00
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
2002-08-21 13:02:26 +00:00
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2007-02-27 16:35:31 +00:00
|
|
|
/* TODO: these are _really_ messed up when fonts are flipped */
|
|
|
|
/* TODO: need to look carefully at these and make sure they are correct */
|
2007-01-31 15:52:53 +00:00
|
|
|
ascender = fabs(((int)ft_size->metrics.ascender) / 64.0);
|
|
|
|
descender = fabs(((int)ft_size->metrics.descender) / 64.0);
|
|
|
|
lineHeight = (int)ft_size->metrics.height / 64.0;
|
2007-02-27 16:35:31 +00:00
|
|
|
xHeight = (int)ft_size->metrics.y_ppem / 64.0;
|
|
|
|
maximumAdvancement = NSMakeSize((ft_size->metrics.max_advance / 64.0), 0.0);
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2006-11-19 11:08:09 +00:00
|
|
|
fontBBox
|
2008-07-12 08:02:37 +00:00
|
|
|
= NSMakeRect(0, -descender, maximumAdvancement.width, ascender + descender);
|
2002-08-21 13:02:26 +00:00
|
|
|
descender = -descender;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
/* printf("(%@) h=%g a=%g d=%g max=(%g %g) (%g %g)+(%g %g)\n",name,
|
|
|
|
xHeight, ascender, descender,
|
|
|
|
maximumAdvancement.width, maximumAdvancement.height,
|
|
|
|
fontBBox.origin.x, fontBBox.origin.y,
|
|
|
|
fontBBox.size.width, fontBBox.size.height);*/
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-01-26 19:07:53 +00:00
|
|
|
{
|
2005-01-11 15:02:29 +00:00
|
|
|
int i;
|
2007-01-31 15:52:53 +00:00
|
|
|
FT_Face face = ft_size->face;
|
2005-01-11 15:02:29 +00:00
|
|
|
FT_CharMap cmap;
|
|
|
|
FT_Encoding e;
|
2010-01-26 09:21:01 +00:00
|
|
|
unicodeCmap = -1;
|
2006-11-19 11:08:09 +00:00
|
|
|
|
2009-01-13 00:34:14 +00:00
|
|
|
if (!face)
|
|
|
|
{
|
|
|
|
NSLog(@"Found no face for font '%@'", name);
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
for (i = 0; i < face->num_charmaps; i++)
|
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
cmap = face->charmaps[i];
|
|
|
|
e = cmap->encoding;
|
|
|
|
if (e == FT_ENCODING_UNICODE)
|
|
|
|
{
|
|
|
|
unicodeCmap = i;
|
|
|
|
break;
|
|
|
|
}
|
2005-01-11 15:02:29 +00:00
|
|
|
}
|
|
|
|
}
|
2003-01-26 19:07:53 +00:00
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
if (screenFont)
|
2003-11-18 16:07:58 +00:00
|
|
|
{
|
2005-01-11 15:02:29 +00:00
|
|
|
int flags;
|
2006-11-19 11:08:09 +00:00
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
if (pix_width == pix_height && pix_width < 16 && pix_height >= 8)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
int rh = face_info->render_hints_hack;
|
|
|
|
|
|
|
|
if (rh & 0x10000)
|
|
|
|
{
|
|
|
|
flags = FT_LOAD_TARGET_NORMAL;
|
|
|
|
rh = (rh >> 8) & 0xff;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
flags = FT_LOAD_TARGET_MONO;
|
|
|
|
rh = rh & 0xff;
|
|
|
|
}
|
|
|
|
if (rh & 1)
|
|
|
|
flags |= FT_LOAD_FORCE_AUTOHINT;
|
|
|
|
if (!(rh & 2))
|
|
|
|
flags |= FT_LOAD_NO_HINTING;
|
|
|
|
}
|
2005-01-11 15:02:29 +00:00
|
|
|
else if (pix_width < 8)
|
2009-01-04 15:56:09 +00:00
|
|
|
flags = FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING;
|
2005-01-11 15:02:29 +00:00
|
|
|
else
|
2009-01-04 15:56:09 +00:00
|
|
|
flags = FT_LOAD_TARGET_NORMAL;
|
2005-01-11 15:02:29 +00:00
|
|
|
imageType.flags = flags;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
imageType.flags = FT_LOAD_NO_HINTING;
|
2003-11-18 16:07:58 +00:00
|
|
|
}
|
|
|
|
|
2004-11-09 21:22:36 +00:00
|
|
|
/*
|
|
|
|
Here, we simply need to make sure that we don't get any false matches
|
|
|
|
the first time a particular cache entry is used. Thus, we only need to
|
|
|
|
initialize the first entry. For all other entries, cachedGlyph[i] will
|
|
|
|
be 0, and that's a glyph that can't possibly hash to any entry except
|
|
|
|
entry #0, so it won't cause any false matches.
|
|
|
|
*/
|
|
|
|
cachedGlyph[0] = 1;
|
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
return self;
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
2009-11-09 10:31:00 +00:00
|
|
|
- (NSString*) displayName
|
|
|
|
{
|
|
|
|
return face_info->displayName;
|
|
|
|
}
|
|
|
|
|
2006-07-04 21:54:48 +00:00
|
|
|
- (void) set
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2006-11-19 11:08:09 +00:00
|
|
|
NSLog(@"ignore -set method of font '%@'", fontName);
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
2007-01-31 15:52:53 +00:00
|
|
|
- (NSCharacterSet*) coveredCharacterSet
|
|
|
|
{
|
|
|
|
if (coveredCharacterSet == nil)
|
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
NSMutableCharacterSet *m = [NSMutableCharacterSet new];
|
|
|
|
unsigned count = 0;
|
|
|
|
FT_Face face;
|
|
|
|
FT_ULong charcode;
|
|
|
|
FT_UInt glyphindex;
|
2007-08-07 16:04:47 +00:00
|
|
|
FT_Size size;
|
|
|
|
|
|
|
|
if (FTC_Manager_LookupSize(ftc_manager, &scaler, &size))
|
|
|
|
return nil;
|
|
|
|
face = size->face;
|
2007-01-31 15:52:53 +00:00
|
|
|
|
2007-08-07 16:04:47 +00:00
|
|
|
charcode = FT_Get_First_Char(face, &glyphindex);
|
2007-01-31 15:52:53 +00:00
|
|
|
if (glyphindex != 0)
|
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
NSRange range;
|
|
|
|
|
2007-08-13 16:08:22 +00:00
|
|
|
range.location = charcode;
|
|
|
|
range.length = 1;
|
|
|
|
|
|
|
|
while (glyphindex != 0)
|
|
|
|
{
|
|
|
|
count++;
|
2007-08-15 13:42:36 +00:00
|
|
|
if (charcode >= 1114112)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2007-08-13 16:08:22 +00:00
|
|
|
if (charcode == NSMaxRange(range))
|
|
|
|
{
|
|
|
|
range.length++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[m addCharactersInRange: range];
|
|
|
|
range.location = charcode;
|
|
|
|
range.length = 1;
|
|
|
|
}
|
|
|
|
charcode = FT_Get_Next_Char(face, charcode, &glyphindex);
|
|
|
|
}
|
|
|
|
if (range.length > 0)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
2007-08-13 16:08:22 +00:00
|
|
|
[m addCharactersInRange: range];
|
2009-01-04 15:56:09 +00:00
|
|
|
}
|
2007-08-13 16:08:22 +00:00
|
|
|
}
|
2007-01-31 15:52:53 +00:00
|
|
|
coveredCharacterSet = [m copy];
|
|
|
|
numberOfGlyphs = count;
|
|
|
|
RELEASE(m);
|
|
|
|
}
|
|
|
|
return coveredCharacterSet;
|
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2010-02-20 16:33:30 +00:00
|
|
|
- (CGFloat) defaultLineHeightForFont
|
2004-09-21 17:26:00 +00:00
|
|
|
{
|
|
|
|
return lineHeight;
|
|
|
|
}
|
|
|
|
|
2020-01-17 15:23:07 +00:00
|
|
|
- (NSUInteger) numberOfGlyphs
|
2007-01-31 15:52:53 +00:00
|
|
|
{
|
|
|
|
if (coveredCharacterSet == nil)
|
|
|
|
{
|
|
|
|
[self coveredCharacterSet];
|
|
|
|
}
|
|
|
|
return numberOfGlyphs;
|
|
|
|
}
|
2004-09-21 17:26:00 +00:00
|
|
|
|
2002-08-20 16:36:09 +00:00
|
|
|
/* TODO: the current point probably needs updating after drawing is done */
|
|
|
|
|
2005-03-29 05:54:36 +00:00
|
|
|
/* draw string at point, clipped, w/given color and alpha, and possible deltas:
|
|
|
|
flags & 0x1: data contains x offsets, use instead of glyph x advance
|
|
|
|
flags & 0x2: data contains y offsets, use instead of glyph y advance
|
|
|
|
flags & 0x4: data contains a single x and y offset, which should be added to
|
|
|
|
font's advancements for each glyph; results are undefined if
|
|
|
|
this option is combined with either x or y offsets (0x1,0x2)
|
|
|
|
flags & 0x8: data contains a single x and y offset, which should be added to
|
|
|
|
font's advancement for glyph identified by 'wch'; if combined
|
|
|
|
with 0x4 deltas contain exactly two offsets for x and y, the
|
|
|
|
first for every character, the second for 'wch'; results are
|
|
|
|
undefined if 0x8 is combined with 0x2 or 0x1
|
|
|
|
*/
|
2006-07-04 21:54:48 +00:00
|
|
|
- (void) drawString: (const char *)s
|
2006-11-19 11:08:09 +00:00
|
|
|
at: (int)x : (int)y
|
|
|
|
to: (int)x0 : (int)y0 : (int)x1 : (int)y1
|
|
|
|
: (unsigned char *)buf : (int)bpl
|
|
|
|
: (unsigned char *)abuf : (int)abpl
|
|
|
|
color: (unsigned char)r
|
|
|
|
: (unsigned char)g
|
|
|
|
: (unsigned char)b
|
|
|
|
: (unsigned char)alpha
|
|
|
|
transform: (NSAffineTransform *)transform
|
2013-02-05 19:18:49 +00:00
|
|
|
deltas: (const CGFloat *)delta_data : (int)delta_size : (int)delta_flags
|
2006-11-19 11:08:09 +00:00
|
|
|
widthChar: (int) wch
|
|
|
|
drawinfo: (draw_info_t *)di
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2002-08-21 13:02:26 +00:00
|
|
|
const unsigned char *c;
|
|
|
|
unsigned char ch;
|
|
|
|
unsigned int uch;
|
2005-03-29 05:54:36 +00:00
|
|
|
int d;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
unsigned int glyph;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
int use_sbit;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
FTC_SBit sbit;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
FT_Matrix ftmatrix;
|
|
|
|
FT_Vector ftdelta;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-05-11 17:23:43 +00:00
|
|
|
FT_Error error;
|
2009-01-04 15:56:09 +00:00
|
|
|
NSAffineTransformStruct ts;
|
2003-05-11 17:23:43 +00:00
|
|
|
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
if (!alpha)
|
|
|
|
return;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
/* TODO: if we had guaranteed upper bounds on glyph image size we
|
|
|
|
could do some basic clipping here */
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
x1 -= x0;
|
|
|
|
y1 -= y0;
|
|
|
|
x -= x0;
|
|
|
|
y -= y0;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2006-11-19 11:08:09 +00:00
|
|
|
ts = [transform transformStruct];
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
/* NSLog(@"[%@ draw using matrix: (%g %g %g %g %g %g)] transform=%@",
|
|
|
|
self,
|
|
|
|
matrix[0], matrix[1], matrix[2],
|
|
|
|
matrix[3], matrix[4], matrix[5],
|
|
|
|
transform
|
|
|
|
);*/
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
{
|
|
|
|
float xx, xy, yx, yy;
|
|
|
|
|
2006-11-19 11:08:09 +00:00
|
|
|
xx = matrix[0] * ts.m11 + matrix[1] * ts.m21;
|
|
|
|
yx = matrix[0] * ts.m12 + matrix[1] * ts.m22;
|
|
|
|
xy = matrix[2] * ts.m11 + matrix[3] * ts.m21;
|
|
|
|
yy = matrix[2] * ts.m12 + matrix[3] * ts.m22;
|
2002-08-21 13:02:26 +00:00
|
|
|
|
2003-01-26 19:07:53 +00:00
|
|
|
/* If we're drawing 'normal' text (unscaled, unrotated, reasonable
|
|
|
|
size), we can and should use the sbit cache for screen fonts. */
|
2006-11-19 11:08:09 +00:00
|
|
|
if (screenFont
|
|
|
|
&& fabs(xx - ((int)xx)) < 0.01 && fabs(yy - ((int)yy)) < 0.01
|
|
|
|
&& fabs(xy) < 0.01 && fabs(yx) < 0.01
|
|
|
|
&& xx < 72 && yy < 72 && xx > 0.5 && yy > 0.5)
|
2002-08-21 13:02:26 +00:00
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
use_sbit = 1;
|
2002-08-21 13:02:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
float f;
|
|
|
|
use_sbit = 0;
|
|
|
|
|
|
|
|
/* TODO: Think hard about this. Fancy truetype magic can
|
|
|
|
significantly change the outline, e.g. by adding fancy adornments
|
|
|
|
at large sizes. If the font is then scaled down, we should
|
|
|
|
probably set the font size to the original size and scale down
|
|
|
|
using the matrix. This ensures that adornments and such are
|
|
|
|
still present, just scaled down.
|
|
|
|
|
|
|
|
This is somewhat complicated by the fact that we don't have any
|
|
|
|
real size, just a matrix. Thus, we average pix_width and
|
|
|
|
pix_height; we'll get the right answer for normal cases, and
|
|
|
|
we can't really do anything about the weird cases. */
|
2020-01-17 15:23:07 +00:00
|
|
|
f = abs(pix_width) + abs(pix_height);
|
2009-01-04 15:56:09 +00:00
|
|
|
if (f > 1)
|
|
|
|
f = f / 2.0;
|
|
|
|
else
|
|
|
|
f = 1.0;
|
|
|
|
f = (int)f;
|
|
|
|
|
|
|
|
scaler.width = scaler.height = f;
|
|
|
|
ftmatrix.xx = xx / f * 65536.0;
|
|
|
|
ftmatrix.xy = xy / f * 65536.0;
|
|
|
|
ftmatrix.yx = yx / f * 65536.0;
|
|
|
|
ftmatrix.yy = yy / f * 65536.0;
|
|
|
|
ftdelta.x = ftdelta.y = 0;
|
2002-08-21 13:02:26 +00:00
|
|
|
}
|
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
|
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
/* NSLog(@"drawString: '%s' at: %i:%i to: %i:%i:%i:%i:%p",
|
|
|
|
s, x, y, x0, y0, x1, y1, buf);*/
|
2005-08-16 04:02:50 +00:00
|
|
|
d=0;
|
2005-01-21 20:49:29 +00:00
|
|
|
for (c = (const unsigned char *)s; *c; c++)
|
2002-08-21 13:02:26 +00:00
|
|
|
{
|
2002-08-20 16:36:09 +00:00
|
|
|
/* TODO: do the same thing in outlineString:... */
|
2002-08-21 13:02:26 +00:00
|
|
|
ch = *c;
|
|
|
|
if (ch < 0x80)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
uch = ch;
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
else if (ch < 0xc0)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
uch = 0xfffd;
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
else if (ch < 0xe0)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
2002-08-21 13:02:26 +00:00
|
|
|
#define ADD_UTF_BYTE(shift, internal) \
|
|
|
|
ch = *++c; \
|
|
|
|
if (ch >= 0x80 && ch < 0xc0) \
|
|
|
|
{ \
|
|
|
|
uch |= (ch & 0x3f) << shift; \
|
|
|
|
internal \
|
|
|
|
} \
|
|
|
|
else \
|
|
|
|
{ \
|
|
|
|
uch = 0xfffd; \
|
|
|
|
c--; \
|
|
|
|
}
|
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
uch = (ch & 0x1f) << 6;
|
|
|
|
ADD_UTF_BYTE(0,)
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
else if (ch < 0xf0)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
uch = (ch & 0x0f) << 12;
|
|
|
|
ADD_UTF_BYTE(6, ADD_UTF_BYTE(0,))
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
else if (ch < 0xf8)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
uch = (ch & 0x07) << 18;
|
|
|
|
ADD_UTF_BYTE(12, ADD_UTF_BYTE(6, ADD_UTF_BYTE(0,)))
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
else if (ch < 0xfc)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
uch = (ch & 0x03) << 24;
|
|
|
|
ADD_UTF_BYTE(18, ADD_UTF_BYTE(12, ADD_UTF_BYTE(6, ADD_UTF_BYTE(0,))))
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
else if (ch < 0xfe)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
uch = (ch & 0x01) << 30;
|
|
|
|
ADD_UTF_BYTE(24, ADD_UTF_BYTE(18, ADD_UTF_BYTE(12,
|
|
|
|
ADD_UTF_BYTE(6, ADD_UTF_BYTE(0,)))))
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
else
|
2006-11-19 11:08:09 +00:00
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
uch = 0xfffd;
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
#undef ADD_UTF_BYTE
|
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
glyph = FTC_CMapCache_Lookup(ftc_cmapcache, faceId, unicodeCmap, uch);
|
2002-08-21 13:02:26 +00:00
|
|
|
|
|
|
|
if (use_sbit)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
if ((error = FTC_SBitCache_Lookup(ftc_sbitcache, &imageType,
|
|
|
|
glyph, &sbit, NULL)))
|
|
|
|
{
|
|
|
|
NSLog(@"FTC_SBitCache_Lookup() failed with error %08x "
|
|
|
|
@"(%08x, %08x, %ix%i, %08x)",
|
2020-01-17 15:23:07 +00:00
|
|
|
error, glyph, (unsigned)imageType.face_id, imageType.width,
|
2009-01-04 15:56:09 +00:00
|
|
|
imageType.height, imageType.flags);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sbit->buffer)
|
|
|
|
{
|
2005-03-29 05:54:36 +00:00
|
|
|
if (!delta_flags)
|
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
x += sbit->xadvance;
|
2005-03-29 05:54:36 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (delta_flags & 0x1)
|
|
|
|
x += delta_data[d++];
|
|
|
|
if (delta_flags & 0x2)
|
2006-11-19 11:08:09 +00:00
|
|
|
y += (ts.m22 < 0) ?
|
2009-01-04 15:56:09 +00:00
|
|
|
delta_data[d++] : -delta_data[d++];
|
2005-03-29 05:54:36 +00:00
|
|
|
if (delta_flags & 0x4)
|
|
|
|
{
|
|
|
|
x += sbit->xadvance + delta_data[0];
|
2006-11-19 11:08:09 +00:00
|
|
|
y += /*sbit->yadvance +*/ (ts.m22 < 0) ?
|
2009-01-04 15:56:09 +00:00
|
|
|
delta_data[1] : -delta_data[1];
|
2005-03-29 05:54:36 +00:00
|
|
|
if ((delta_flags & 0x8) && (uch == wch))
|
|
|
|
{
|
|
|
|
x += delta_data[2];
|
2006-11-19 11:08:09 +00:00
|
|
|
y += (ts.m22 < 0) ? delta_data[3] : -delta_data[3];
|
2005-03-29 05:54:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (delta_flags & 0x8)
|
|
|
|
{
|
|
|
|
if (uch == wch)
|
|
|
|
{
|
|
|
|
x += sbit->xadvance + delta_data[0];
|
2006-11-19 11:08:09 +00:00
|
|
|
y += /*sbit->yadvance +*/ (ts.m22 < 0) ?
|
2005-03-29 05:54:36 +00:00
|
|
|
delta_data[1] : -delta_data[1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x += sbit->xadvance;
|
|
|
|
/*y += sbit->yadvance;*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-01-04 15:56:09 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sbit->format == ft_pixel_mode_grays)
|
|
|
|
{
|
|
|
|
int gx = x + sbit->left, gy = y - sbit->top;
|
|
|
|
int sbpl = sbit->pitch;
|
|
|
|
int sx = sbit->width, sy = sbit->height;
|
|
|
|
const unsigned char *src = sbit->buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (gx < 0)
|
|
|
|
{
|
|
|
|
sx += gx;
|
|
|
|
src -= gx;
|
|
|
|
gx = 0;
|
|
|
|
}
|
|
|
|
else if (gx > 0)
|
|
|
|
{
|
|
|
|
dst += DI.bytes_per_pixel * gx;
|
|
|
|
}
|
|
|
|
|
|
|
|
sx += gx;
|
|
|
|
if (sx > x1)
|
|
|
|
sx = x1;
|
|
|
|
sx -= gx;
|
|
|
|
|
|
|
|
if (sx > 0)
|
|
|
|
{
|
|
|
|
if (alpha >= 255)
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_ALPHA_OPAQUE(dst, src, r, g, b, sx);
|
|
|
|
else
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_ALPHA(dst, src, r, g, b, alpha, sx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (sbit->format == ft_pixel_mode_mono)
|
|
|
|
{
|
|
|
|
int gx = x + sbit->left, gy = y - sbit->top;
|
|
|
|
int sbpl = sbit->pitch;
|
|
|
|
int sx = sbit->width, sy = sbit->height;
|
|
|
|
const unsigned char *src = sbit->buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
int src_ofs = 0;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (gx < 0)
|
|
|
|
{
|
|
|
|
sx += gx;
|
|
|
|
src -= gx / 8;
|
|
|
|
src_ofs = (-gx) & 7;
|
|
|
|
gx = 0;
|
|
|
|
}
|
|
|
|
else if (gx > 0)
|
|
|
|
{
|
|
|
|
dst += DI.bytes_per_pixel * gx;
|
|
|
|
}
|
|
|
|
|
|
|
|
sx += gx;
|
|
|
|
if (sx > x1)
|
|
|
|
sx = x1;
|
|
|
|
sx -= gx;
|
|
|
|
|
|
|
|
if (sx > 0)
|
|
|
|
{
|
|
|
|
if (alpha >= 255)
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_MONO_OPAQUE(dst, src, src_ofs, r, g, b, sx);
|
|
|
|
else
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_MONO(dst, src, src_ofs, r, g, b, alpha, sx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"unhandled font bitmap format %i", sbit->format);
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
|
2005-03-29 05:54:36 +00:00
|
|
|
if (!delta_flags)
|
|
|
|
{
|
|
|
|
x += sbit->xadvance;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (delta_flags & 0x1)
|
|
|
|
x += delta_data[d++];
|
|
|
|
if (delta_flags & 0x2)
|
2006-11-19 11:08:09 +00:00
|
|
|
y += (ts.m22 < 0) ? delta_data[d++] : -delta_data[d++];
|
2005-03-29 05:54:36 +00:00
|
|
|
if (delta_flags & 0x4)
|
|
|
|
{
|
|
|
|
x += sbit->xadvance + delta_data[0];
|
2006-11-19 11:08:09 +00:00
|
|
|
y += /*sbit->yadvance +*/ (ts.m22 < 0) ?
|
2005-03-29 05:54:36 +00:00
|
|
|
delta_data[1] : -delta_data[1];
|
|
|
|
if ((delta_flags & 0x8) && (uch == wch))
|
|
|
|
{
|
|
|
|
x += delta_data[2];
|
2006-11-19 11:08:09 +00:00
|
|
|
y += (ts.m22 < 0) ? delta_data[3] : -delta_data[3];
|
2005-03-29 05:54:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (delta_flags & 0x8)
|
|
|
|
{
|
|
|
|
if (uch == wch)
|
|
|
|
{
|
|
|
|
x += sbit->xadvance + delta_data[0];
|
2006-11-19 11:08:09 +00:00
|
|
|
y += /*sbit->yadvance +*/ (ts.m22 < 0) ?
|
2005-03-29 05:54:36 +00:00
|
|
|
delta_data[1] : -delta_data[1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x += sbit->xadvance;
|
|
|
|
/*y += sbit->yadvance;*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-01-04 15:56:09 +00:00
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
else
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
FT_Face face;
|
|
|
|
FT_Glyph gl;
|
|
|
|
FT_Size size;
|
|
|
|
FT_BitmapGlyph gb;
|
|
|
|
|
|
|
|
if ((error=FTC_Manager_LookupSize(ftc_manager, &scaler, &size)))
|
|
|
|
{
|
|
|
|
NSLog(@"FTC_Manager_Lookup_Size() failed with error %08x", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
face = size->face;
|
|
|
|
|
|
|
|
/* TODO: for screen fonts we should probably still hint */
|
|
|
|
if ((error=FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Load_Glyph() failed with error %08x", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error=FT_Get_Glyph(face->glyph, &gl)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Get_Glyph() failed with error %08x", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error=FT_Glyph_Transform(gl, &ftmatrix, &ftdelta)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Glyph_Transform() failed with error %08x", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((error=FT_Glyph_To_Bitmap(&gl, ft_render_mode_normal, 0, 1)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Glyph_To_Bitmap() failed with error %08x", error);
|
|
|
|
FT_Done_Glyph(gl);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
gb = (FT_BitmapGlyph)gl;
|
|
|
|
|
|
|
|
|
|
|
|
if (gb->bitmap.pixel_mode == ft_pixel_mode_grays)
|
|
|
|
{
|
|
|
|
int gx = x + gb->left, gy = y - gb->top;
|
|
|
|
int sbpl = gb->bitmap.pitch;
|
|
|
|
int sx = gb->bitmap.width, sy = gb->bitmap.rows;
|
|
|
|
const unsigned char *src = gb->bitmap.buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
unsigned char *dsta = abuf;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
if (dsta)
|
|
|
|
dsta += abpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (gx < 0)
|
|
|
|
{
|
|
|
|
sx += gx;
|
|
|
|
src -= gx;
|
|
|
|
gx = 0;
|
|
|
|
}
|
|
|
|
else if (gx > 0)
|
|
|
|
{
|
|
|
|
dst += DI.bytes_per_pixel * gx;
|
|
|
|
if (dsta)
|
|
|
|
dsta += gx;
|
|
|
|
}
|
|
|
|
|
|
|
|
sx += gx;
|
|
|
|
if (sx > x1)
|
|
|
|
sx = x1;
|
|
|
|
sx -= gx;
|
|
|
|
|
|
|
|
if (sx > 0)
|
|
|
|
{
|
|
|
|
if (dsta)
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl, dsta += abpl)
|
|
|
|
RENDER_BLIT_ALPHA_A(dst, dsta, src, r, g, b, alpha, sx);
|
|
|
|
else if (alpha >= 255)
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_ALPHA_OPAQUE(dst, src, r, g, b, sx);
|
|
|
|
else
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_ALPHA(dst, src, r, g, b, alpha, sx);
|
|
|
|
}
|
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
/* TODO: will this case ever appear? */
|
2009-01-04 15:56:09 +00:00
|
|
|
/* else if (gb->bitmap.pixel_mode==ft_pixel_mode_mono)*/
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"unhandled font bitmap format %i", gb->bitmap.pixel_mode);
|
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2005-03-29 05:54:36 +00:00
|
|
|
if (!delta_flags)
|
|
|
|
{
|
|
|
|
ftdelta.x += gl->advance.x >> 10;
|
|
|
|
ftdelta.y += gl->advance.y >> 10;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (delta_flags & 0x1)
|
|
|
|
ftdelta.x += delta_data[d++] * 64.0;
|
|
|
|
if (delta_flags & 0x2)
|
|
|
|
ftdelta.y += delta_data[d++] * 64.0;
|
|
|
|
if (delta_flags & 0x4)
|
|
|
|
{
|
|
|
|
ftdelta.x += (gl->advance.x >> 10) + delta_data[0] * 64.0;
|
|
|
|
ftdelta.y += (gl->advance.y >> 10) + delta_data[1] * 64.0;
|
|
|
|
if ((delta_flags & 0x8) && (uch == wch))
|
|
|
|
{
|
|
|
|
ftdelta.x += delta_data[2] * 64.0;
|
|
|
|
ftdelta.y += delta_data[3] * 64.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (delta_flags & 0x8)
|
|
|
|
{
|
|
|
|
if (uch == wch)
|
|
|
|
{
|
|
|
|
ftdelta.x += (gl->advance.x >> 10) + delta_data[0] * 64.0;
|
|
|
|
ftdelta.y += (gl->advance.y >> 10) + delta_data[1] * 64.0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ftdelta.x += gl->advance.x >> 10;
|
|
|
|
ftdelta.y += gl->advance.y >> 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
FT_Done_Glyph(gl);
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-07-04 21:54:48 +00:00
|
|
|
- (void) drawGlyphs: (const NSGlyph *)glyphs : (int)length
|
2009-01-04 15:56:09 +00:00
|
|
|
at: (int)x : (int)y
|
|
|
|
to: (int)x0 : (int)y0 : (int)x1 : (int)y1
|
|
|
|
: (unsigned char *)buf : (int)bpl
|
|
|
|
color: (unsigned char)r : (unsigned char)g : (unsigned char)b
|
|
|
|
: (unsigned char)alpha
|
|
|
|
transform: (NSAffineTransform *)transform
|
|
|
|
drawinfo: (struct draw_info_s *)di
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2002-08-21 13:02:26 +00:00
|
|
|
unsigned int glyph;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-01-26 19:07:53 +00:00
|
|
|
int use_sbit;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-01-26 19:07:53 +00:00
|
|
|
FTC_SBit sbit;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-01-26 19:07:53 +00:00
|
|
|
FT_Matrix ftmatrix;
|
|
|
|
FT_Vector ftdelta;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-05-11 17:23:43 +00:00
|
|
|
FT_Error error;
|
2009-01-04 15:56:09 +00:00
|
|
|
NSAffineTransformStruct ts;
|
2003-05-11 17:23:43 +00:00
|
|
|
|
2003-01-26 19:07:53 +00:00
|
|
|
|
|
|
|
if (!alpha)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* TODO: if we had guaranteed upper bounds on glyph image size we
|
|
|
|
could do some basic clipping here */
|
|
|
|
|
|
|
|
x1 -= x0;
|
|
|
|
y1 -= y0;
|
|
|
|
x -= x0;
|
|
|
|
y -= y0;
|
|
|
|
|
2006-11-19 11:08:09 +00:00
|
|
|
ts = [transform transformStruct];
|
2003-01-26 19:07:53 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
/* NSLog(@"[%@ draw using matrix: (%g %g %g %g %g %g)] transform=%@",
|
|
|
|
self,
|
|
|
|
matrix[0], matrix[1], matrix[2],
|
|
|
|
matrix[3], matrix[4], matrix[5],
|
|
|
|
transform
|
|
|
|
);*/
|
2003-01-26 19:07:53 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
float xx, xy, yx, yy;
|
|
|
|
|
2006-11-19 11:08:09 +00:00
|
|
|
xx = matrix[0] * ts.m11 + matrix[1] * ts.m21;
|
|
|
|
yx = matrix[0] * ts.m12 + matrix[1] * ts.m22;
|
|
|
|
xy = matrix[2] * ts.m11 + matrix[3] * ts.m21;
|
|
|
|
yy = matrix[2] * ts.m12 + matrix[3] * ts.m22;
|
2003-01-26 19:07:53 +00:00
|
|
|
|
|
|
|
/* If we're drawing 'normal' text (unscaled, unrotated, reasonable
|
|
|
|
size), we can and should use the sbit cache for screen fonts. */
|
2006-11-19 11:08:09 +00:00
|
|
|
if (screenFont
|
|
|
|
&& fabs(xx - ((int)xx)) < 0.01 && fabs(yy - ((int)yy)) < 0.01
|
|
|
|
&& fabs(xy) < 0.01 && fabs(yx) < 0.01
|
|
|
|
&& xx < 72 && yy < 72 && xx > 0.5 && yy > 0.5)
|
2003-01-26 19:07:53 +00:00
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
use_sbit = 1;
|
2003-01-26 19:07:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
float f;
|
|
|
|
use_sbit = 0;
|
|
|
|
|
2020-01-17 15:23:07 +00:00
|
|
|
f = abs(pix_width) + abs(pix_height);
|
2009-01-04 15:56:09 +00:00
|
|
|
if (f > 1)
|
|
|
|
f = f / 2.0;
|
|
|
|
else
|
|
|
|
f = 1.0;
|
|
|
|
f = (int)f;
|
|
|
|
|
|
|
|
scaler.width = scaler.height = f;
|
|
|
|
ftmatrix.xx = xx / f * 65536.0;
|
|
|
|
ftmatrix.xy = xy / f * 65536.0;
|
|
|
|
ftmatrix.yx = yx / f * 65536.0;
|
|
|
|
ftmatrix.yy = yy / f * 65536.0;
|
|
|
|
ftdelta.x = ftdelta.y = 0;
|
2003-01-26 19:07:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
/* NSLog(@"drawGlyphs: '%p' at: %i:%i to: %i:%i:%i:%i:%p",
|
|
|
|
glyphs, x, y, x0, y0, x1, y1, buf);*/
|
2003-01-26 19:07:53 +00:00
|
|
|
|
|
|
|
for (; length; length--, glyphs++)
|
2002-08-21 13:02:26 +00:00
|
|
|
{
|
2003-03-03 19:06:55 +00:00
|
|
|
glyph = *glyphs - 1;
|
2003-01-26 19:07:53 +00:00
|
|
|
|
|
|
|
if (use_sbit)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
if ((error = FTC_SBitCache_Lookup(ftc_sbitcache, &imageType,
|
|
|
|
glyph, &sbit, NULL)))
|
|
|
|
{
|
|
|
|
NSLog(@"FTC_SBitCache_Lookup() failed with error %08x "
|
|
|
|
@"(%08x, %08x, %ix%i, %08x)",
|
2020-01-17 15:23:07 +00:00
|
|
|
error, glyph, (unsigned)imageType.face_id,
|
2009-01-04 15:56:09 +00:00
|
|
|
imageType.width, imageType.height,
|
|
|
|
imageType.flags);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sbit->buffer)
|
|
|
|
{
|
|
|
|
x += sbit->xadvance;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sbit->format == ft_pixel_mode_grays)
|
|
|
|
{
|
|
|
|
int gx = x + sbit->left, gy = y - sbit->top;
|
|
|
|
int sbpl = sbit->pitch;
|
|
|
|
int sx = sbit->width, sy = sbit->height;
|
|
|
|
const unsigned char *src = sbit->buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (gx < 0)
|
|
|
|
{
|
|
|
|
sx += gx;
|
|
|
|
src -= gx;
|
|
|
|
gx = 0;
|
|
|
|
}
|
|
|
|
else if (gx > 0)
|
|
|
|
{
|
|
|
|
dst += DI.bytes_per_pixel * gx;
|
|
|
|
}
|
|
|
|
|
|
|
|
sx += gx;
|
|
|
|
if (sx > x1)
|
|
|
|
sx = x1;
|
|
|
|
sx -= gx;
|
|
|
|
|
|
|
|
if (sx > 0)
|
|
|
|
{
|
|
|
|
if (alpha >= 255)
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_ALPHA_OPAQUE(dst, src, r, g, b, sx);
|
|
|
|
else
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_ALPHA(dst, src, r, g, b, alpha, sx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (sbit->format == ft_pixel_mode_mono)
|
|
|
|
{
|
|
|
|
int gx = x + sbit->left, gy = y - sbit->top;
|
|
|
|
int sbpl = sbit->pitch;
|
|
|
|
int sx = sbit->width, sy = sbit->height;
|
|
|
|
const unsigned char *src = sbit->buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
int src_ofs = 0;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (gx < 0)
|
|
|
|
{
|
|
|
|
sx += gx;
|
|
|
|
src -= gx / 8;
|
|
|
|
src_ofs = (-gx) & 7;
|
|
|
|
gx = 0;
|
|
|
|
}
|
|
|
|
else if (gx > 0)
|
|
|
|
{
|
|
|
|
dst += DI.bytes_per_pixel * gx;
|
|
|
|
}
|
|
|
|
|
|
|
|
sx += gx;
|
|
|
|
if (sx > x1)
|
|
|
|
sx = x1;
|
|
|
|
sx -= gx;
|
|
|
|
|
|
|
|
if (sx > 0)
|
|
|
|
{
|
|
|
|
if (alpha >= 255)
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_MONO_OPAQUE(dst, src, src_ofs, r, g, b, sx);
|
|
|
|
else
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_MONO(dst, src, src_ofs, r, g, b, alpha, sx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"unhandled font bitmap format %i", sbit->format);
|
|
|
|
}
|
|
|
|
|
|
|
|
x += sbit->xadvance;
|
|
|
|
}
|
2003-01-26 19:07:53 +00:00
|
|
|
else
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
FT_Face face;
|
|
|
|
FT_Size size;
|
|
|
|
FT_Glyph gl;
|
|
|
|
FT_BitmapGlyph gb;
|
|
|
|
|
|
|
|
if ((error=FTC_Manager_LookupSize(ftc_manager, &scaler, &size)))
|
|
|
|
{
|
|
|
|
NSLog(@"FTC_Manager_Lookup_Size() failed with error %08x",error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
face = size->face;
|
|
|
|
|
|
|
|
/* TODO: for screen fonts ...see above... rotations of 90, 180, 270,
|
|
|
|
* and integer scales hinting might still be a good idea. */
|
|
|
|
if ((error = FT_Load_Glyph(face, glyph,
|
|
|
|
FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Load_Glyph() failed with error %08x", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error=FT_Get_Glyph(face->glyph, &gl)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Get_Glyph() failed with error %08x", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error=FT_Glyph_Transform(gl, &ftmatrix, &ftdelta)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Glyph_Transform() failed with error %08x", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((error=FT_Glyph_To_Bitmap(&gl, ft_render_mode_normal, 0, 1)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Glyph_To_Bitmap() failed with error %08x", error);
|
|
|
|
FT_Done_Glyph(gl);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
gb = (FT_BitmapGlyph)gl;
|
|
|
|
|
|
|
|
|
|
|
|
if (gb->bitmap.pixel_mode == ft_pixel_mode_grays)
|
|
|
|
{
|
|
|
|
int gx = x + gb->left, gy = y - gb->top;
|
|
|
|
int sbpl = gb->bitmap.pitch;
|
|
|
|
int sx = gb->bitmap.width, sy = gb->bitmap.rows;
|
|
|
|
const unsigned char *src = gb->bitmap.buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (gx < 0)
|
|
|
|
{
|
|
|
|
sx += gx;
|
|
|
|
src -= gx;
|
|
|
|
gx = 0;
|
|
|
|
}
|
|
|
|
else if (gx > 0)
|
|
|
|
{
|
|
|
|
dst += DI.bytes_per_pixel * gx;
|
|
|
|
}
|
|
|
|
|
|
|
|
sx += gx;
|
|
|
|
if (sx > x1)
|
|
|
|
sx = x1;
|
|
|
|
sx -= gx;
|
|
|
|
|
|
|
|
if (sx > 0)
|
|
|
|
{
|
|
|
|
if (alpha >= 255)
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_ALPHA_OPAQUE(dst, src, r, g, b, sx);
|
|
|
|
else
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_ALPHA(dst, src, r, g, b, alpha, sx);
|
|
|
|
}
|
|
|
|
}
|
2003-01-26 19:07:53 +00:00
|
|
|
/* TODO: will this case ever appear? */
|
2009-01-04 15:56:09 +00:00
|
|
|
/* else if (gb->bitmap.pixel_mode==ft_pixel_mode_mono)*/
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"unhandled font bitmap format %i", gb->bitmap.pixel_mode);
|
|
|
|
}
|
2004-02-29 20:45:05 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
ftdelta.x += gl->advance.x >> 10;
|
|
|
|
ftdelta.y += gl->advance.y >> 10;
|
2004-02-29 20:45:05 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
FT_Done_Glyph(gl);
|
|
|
|
}
|
2004-02-29 20:45:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-04 21:54:48 +00:00
|
|
|
- (void) drawGlyphs: (const NSGlyph *)glyphs : (int)length
|
2009-01-04 15:56:09 +00:00
|
|
|
at: (int)x : (int)y
|
|
|
|
to: (int)x0 : (int)y0 : (int)x1 : (int)y1
|
|
|
|
: (unsigned char *)buf : (int)bpl
|
|
|
|
alpha: (unsigned char *)abuf : (int)abpl
|
|
|
|
color: (unsigned char)r : (unsigned char)g : (unsigned char)b
|
|
|
|
: (unsigned char)alpha
|
|
|
|
transform: (NSAffineTransform *)transform
|
|
|
|
drawinfo: (struct draw_info_s *)di
|
2004-02-29 20:45:05 +00:00
|
|
|
{
|
|
|
|
unsigned int glyph;
|
|
|
|
|
|
|
|
int use_sbit;
|
|
|
|
|
|
|
|
FTC_SBit sbit;
|
|
|
|
|
|
|
|
FT_Matrix ftmatrix;
|
|
|
|
FT_Vector ftdelta;
|
|
|
|
|
|
|
|
FT_Error error;
|
2009-01-04 15:56:09 +00:00
|
|
|
NSAffineTransformStruct ts;
|
2004-02-29 20:45:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (!alpha)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* TODO: if we had guaranteed upper bounds on glyph image size we
|
|
|
|
could do some basic clipping here */
|
|
|
|
|
|
|
|
x1 -= x0;
|
|
|
|
y1 -= y0;
|
|
|
|
x -= x0;
|
|
|
|
y -= y0;
|
|
|
|
|
2006-11-19 11:08:09 +00:00
|
|
|
ts = [transform transformStruct];
|
2004-02-29 20:45:05 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
/* NSLog(@"[%@ draw using matrix: (%g %g %g %g %g %g)] transform=%@",
|
|
|
|
self,
|
|
|
|
matrix[0], matrix[1], matrix[2],
|
|
|
|
matrix[3], matrix[4], matrix[5],
|
|
|
|
transform
|
|
|
|
);*/
|
2004-02-29 20:45:05 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
float xx, xy, yx, yy;
|
|
|
|
|
2006-11-19 11:08:09 +00:00
|
|
|
xx = matrix[0] * ts.m11 + matrix[1] * ts.m21;
|
|
|
|
yx = matrix[0] * ts.m12 + matrix[1] * ts.m22;
|
|
|
|
xy = matrix[2] * ts.m11 + matrix[3] * ts.m21;
|
|
|
|
yy = matrix[2] * ts.m12 + matrix[3] * ts.m22;
|
2004-02-29 20:45:05 +00:00
|
|
|
|
|
|
|
/* If we're drawing 'normal' text (unscaled, unrotated, reasonable
|
|
|
|
size), we can and should use the sbit cache for screen fonts. */
|
2006-11-19 11:08:09 +00:00
|
|
|
if (screenFont
|
|
|
|
&& fabs(xx - ((int)xx)) < 0.01 && fabs(yy - ((int)yy)) < 0.01
|
|
|
|
&& fabs(xy) < 0.01 && fabs(yx) < 0.01
|
|
|
|
&& xx < 72 && yy < 72 && xx > 0.5 && yy > 0.5)
|
2004-02-29 20:45:05 +00:00
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
use_sbit = 1;
|
2004-02-29 20:45:05 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
float f;
|
|
|
|
use_sbit = 0;
|
|
|
|
|
2020-01-17 15:23:07 +00:00
|
|
|
f = abs(pix_width) + abs(pix_height);
|
2009-01-04 15:56:09 +00:00
|
|
|
if (f > 1)
|
|
|
|
f = f / 2.0;
|
|
|
|
else
|
|
|
|
f = 1.0;
|
|
|
|
f = (int)f;
|
|
|
|
|
|
|
|
scaler.width = scaler.height = f;
|
|
|
|
ftmatrix.xx = xx / f * 65536.0;
|
|
|
|
ftmatrix.xy = xy / f * 65536.0;
|
|
|
|
ftmatrix.yx = yx / f * 65536.0;
|
|
|
|
ftmatrix.yy = yy / f * 65536.0;
|
|
|
|
ftdelta.x = ftdelta.y = 0;
|
2004-02-29 20:45:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
/* NSLog(@"drawString: '%s' at: %i:%i to: %i:%i:%i:%i:%p",
|
|
|
|
s, x, y, x0, y0, x1, y1, buf);*/
|
2004-02-29 20:45:05 +00:00
|
|
|
|
|
|
|
for (; length; length--, glyphs++)
|
|
|
|
{
|
|
|
|
glyph = *glyphs - 1;
|
|
|
|
|
|
|
|
if (use_sbit)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
if ((error = FTC_SBitCache_Lookup(ftc_sbitcache, &imageType, glyph, &sbit, NULL)))
|
|
|
|
{
|
|
|
|
if (glyph != 0xffffffff)
|
|
|
|
NSLog(@"FTC_SBitCache_Lookup() failed with error %08x (%08x, %08x, %ix%i, %08x)",
|
2020-01-17 15:23:07 +00:00
|
|
|
error, glyph, (unsigned)imageType.face_id, imageType.width, imageType.height,
|
2009-01-04 15:56:09 +00:00
|
|
|
imageType.flags
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sbit->buffer)
|
|
|
|
{
|
|
|
|
x += sbit->xadvance;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sbit->format == ft_pixel_mode_grays)
|
|
|
|
{
|
|
|
|
int gx = x + sbit->left, gy = y - sbit->top;
|
|
|
|
int sbpl = sbit->pitch;
|
|
|
|
int sx = sbit->width, sy = sbit->height;
|
|
|
|
const unsigned char *src = sbit->buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
unsigned char *adst = abuf;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
adst += abpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (gx < 0)
|
|
|
|
{
|
|
|
|
sx += gx;
|
|
|
|
src -= gx;
|
|
|
|
gx = 0;
|
|
|
|
}
|
|
|
|
else if (gx > 0)
|
|
|
|
{
|
|
|
|
dst += DI.bytes_per_pixel * gx;
|
|
|
|
adst += gx;
|
|
|
|
}
|
|
|
|
|
|
|
|
sx += gx;
|
|
|
|
if (sx > x1)
|
|
|
|
sx = x1;
|
|
|
|
sx -= gx;
|
|
|
|
|
|
|
|
if (sx > 0)
|
|
|
|
{
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl, adst += abpl)
|
|
|
|
RENDER_BLIT_ALPHA_A(dst, adst, src, r, g, b, alpha, sx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (sbit->format == ft_pixel_mode_mono)
|
|
|
|
{
|
|
|
|
int gx = x + sbit->left, gy = y - sbit->top;
|
|
|
|
int sbpl = sbit->pitch;
|
|
|
|
int sx = sbit->width, sy = sbit->height;
|
|
|
|
const unsigned char *src = sbit->buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
unsigned char *adst = abuf;
|
|
|
|
int src_ofs = 0;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
adst += abpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (gx < 0)
|
|
|
|
{
|
|
|
|
sx += gx;
|
|
|
|
src -= gx / 8;
|
|
|
|
src_ofs = (-gx) & 7;
|
|
|
|
gx = 0;
|
|
|
|
}
|
|
|
|
else if (gx > 0)
|
|
|
|
{
|
|
|
|
dst += DI.bytes_per_pixel * gx;
|
|
|
|
adst += gx;
|
|
|
|
}
|
|
|
|
|
|
|
|
sx += gx;
|
|
|
|
if (sx > x1)
|
|
|
|
sx = x1;
|
|
|
|
sx -= gx;
|
|
|
|
|
|
|
|
if (sx > 0)
|
|
|
|
{
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl, adst += bpl)
|
|
|
|
RENDER_BLIT_MONO_A(dst, adst, src, src_ofs, r, g, b, alpha, sx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"unhandled font bitmap format %i", sbit->format);
|
|
|
|
}
|
|
|
|
|
|
|
|
x += sbit->xadvance;
|
|
|
|
}
|
2004-02-29 20:45:05 +00:00
|
|
|
else
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
FT_Face face;
|
|
|
|
FT_Size size;
|
|
|
|
FT_Glyph gl;
|
|
|
|
FT_BitmapGlyph gb;
|
|
|
|
|
|
|
|
if ((error=FTC_Manager_LookupSize(ftc_manager, &scaler, &size)))
|
|
|
|
{
|
|
|
|
NSLog(@"FTC_Manager_Lookup_Size() failed with error %08x", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
face = size->face;
|
|
|
|
|
|
|
|
/* TODO: for screen fonts, see above, etc., rotations of 90, 180, 270, and integer
|
|
|
|
scales hinting might still be a good idea. */
|
|
|
|
if ((error=FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Load_Glyph() failed with error %08x", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error=FT_Get_Glyph(face->glyph, &gl)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Get_Glyph() failed with error %08x", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error=FT_Glyph_Transform(gl, &ftmatrix, &ftdelta)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Glyph_Transform() failed with error %08x", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((error=FT_Glyph_To_Bitmap(&gl, ft_render_mode_normal, 0, 1)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Glyph_To_Bitmap() failed with error %08x", error);
|
|
|
|
FT_Done_Glyph(gl);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
gb = (FT_BitmapGlyph)gl;
|
|
|
|
|
|
|
|
|
|
|
|
if (gb->bitmap.pixel_mode == ft_pixel_mode_grays)
|
|
|
|
{
|
|
|
|
int gx = x + gb->left, gy = y - gb->top;
|
|
|
|
int sbpl = gb->bitmap.pitch;
|
|
|
|
int sx = gb->bitmap.width, sy = gb->bitmap.rows;
|
|
|
|
const unsigned char *src = gb->bitmap.buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
unsigned char *adst = abuf;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
adst += abpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (gx < 0)
|
|
|
|
{
|
|
|
|
sx += gx;
|
|
|
|
src -= gx;
|
|
|
|
gx = 0;
|
|
|
|
}
|
|
|
|
else if (gx > 0)
|
|
|
|
{
|
|
|
|
dst += DI.bytes_per_pixel * gx;
|
|
|
|
adst += gx;
|
|
|
|
}
|
|
|
|
|
|
|
|
sx += gx;
|
|
|
|
if (sx > x1)
|
|
|
|
sx = x1;
|
|
|
|
sx -= gx;
|
|
|
|
|
|
|
|
if (sx > 0)
|
|
|
|
{
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl, adst += bpl)
|
|
|
|
RENDER_BLIT_ALPHA_A(dst, adst, src, r, g, b, alpha, sx);
|
|
|
|
}
|
|
|
|
}
|
2004-02-29 20:45:05 +00:00
|
|
|
/* TODO: will this case ever appear? */
|
2009-01-04 15:56:09 +00:00
|
|
|
/* else if (gb->bitmap.pixel_mode==ft_pixel_mode_mono)*/
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"unhandled font bitmap format %i", gb->bitmap.pixel_mode);
|
|
|
|
}
|
2003-01-26 19:07:53 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
ftdelta.x += gl->advance.x >> 10;
|
|
|
|
ftdelta.y += gl->advance.y >> 10;
|
2003-01-26 19:07:53 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
FT_Done_Glyph(gl);
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
}
|
2003-01-26 19:07:53 +00:00
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-01-26 19:07:53 +00:00
|
|
|
|
2006-07-04 21:54:48 +00:00
|
|
|
- (BOOL) glyphIsEncoded: (NSGlyph)glyph
|
2003-02-10 17:46:06 +00:00
|
|
|
{
|
|
|
|
FT_Face face;
|
2005-01-11 15:02:29 +00:00
|
|
|
FT_Size size;
|
2003-05-11 17:23:43 +00:00
|
|
|
FT_Error error;
|
2003-02-10 17:46:06 +00:00
|
|
|
|
2003-03-03 19:06:55 +00:00
|
|
|
glyph--;
|
2005-01-11 15:02:29 +00:00
|
|
|
if ((error=FTC_Manager_LookupSize(ftc_manager, &scaler, &size)))
|
2003-05-11 17:23:43 +00:00
|
|
|
{
|
|
|
|
NSLog(@"FTC_Manager_Lookup_Size() failed with error %08x",error);
|
|
|
|
return NO;
|
|
|
|
}
|
2005-01-11 15:02:29 +00:00
|
|
|
face = size->face;
|
2003-02-10 17:46:06 +00:00
|
|
|
|
2003-05-11 17:23:43 +00:00
|
|
|
if ((error=FT_Load_Glyph(face, glyph, 0)))
|
|
|
|
{
|
|
|
|
NSLog(@"FT_Load_Glyph() failed with error %08x",error);
|
|
|
|
return NO;
|
|
|
|
}
|
2003-02-10 17:46:06 +00:00
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-01-26 19:07:53 +00:00
|
|
|
- (NSSize) advancementForGlyph: (NSGlyph)glyph
|
|
|
|
{
|
2003-05-11 17:23:43 +00:00
|
|
|
FT_Error error;
|
|
|
|
|
2004-05-13 15:14:46 +00:00
|
|
|
if (glyph == NSControlGlyph
|
2004-11-09 21:22:36 +00:00
|
|
|
|| glyph == GSAttachmentGlyph)
|
2004-05-13 15:14:46 +00:00
|
|
|
return NSZeroSize;
|
|
|
|
|
2004-11-09 21:22:36 +00:00
|
|
|
if (glyph != NSNullGlyph)
|
|
|
|
glyph--;
|
2003-01-26 19:07:53 +00:00
|
|
|
if (screenFont)
|
2002-08-21 13:02:26 +00:00
|
|
|
{
|
2003-11-18 16:07:58 +00:00
|
|
|
int entry = glyph % CACHE_SIZE;
|
2003-01-26 19:07:53 +00:00
|
|
|
FTC_SBit sbit;
|
|
|
|
|
2003-11-18 16:07:58 +00:00
|
|
|
if (cachedGlyph[entry] == glyph)
|
2009-01-04 15:56:09 +00:00
|
|
|
return cachedSize[entry];
|
2003-01-26 19:07:53 +00:00
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
if ((error = FTC_SBitCache_Lookup(ftc_sbitcache, &imageType, glyph, &sbit, NULL)))
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
NSLog(@"FTC_SBitCache_Lookup() failed with error %08x (%08x, %08x, %ix%i, %08x)",
|
2020-01-17 15:23:07 +00:00
|
|
|
error, glyph, (unsigned)imageType.face_id,
|
2009-01-04 15:56:09 +00:00
|
|
|
imageType.width, imageType.height,
|
|
|
|
imageType.flags
|
|
|
|
);
|
|
|
|
return NSZeroSize;
|
|
|
|
}
|
2003-01-26 19:07:53 +00:00
|
|
|
|
2003-11-18 16:07:58 +00:00
|
|
|
cachedGlyph[entry] = glyph;
|
|
|
|
cachedSize[entry] = NSMakeSize(sbit->xadvance, sbit->yadvance);
|
|
|
|
return cachedSize[entry];
|
2002-08-21 13:02:26 +00:00
|
|
|
}
|
2003-01-26 19:07:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
FT_Face face;
|
2005-01-11 15:02:29 +00:00
|
|
|
FT_Size size;
|
2003-01-26 19:07:53 +00:00
|
|
|
FT_Glyph gl;
|
|
|
|
FT_Matrix ftmatrix;
|
|
|
|
FT_Vector ftdelta;
|
|
|
|
float f;
|
|
|
|
NSSize s;
|
|
|
|
|
|
|
|
f = fabs(matrix[0] * matrix[3] - matrix[1] * matrix[2]);
|
|
|
|
if (f > 1)
|
2009-01-04 15:56:09 +00:00
|
|
|
f = sqrt(f);
|
2003-01-26 19:07:53 +00:00
|
|
|
else
|
2009-01-04 15:56:09 +00:00
|
|
|
f = 1.0;
|
2003-01-26 19:07:53 +00:00
|
|
|
|
|
|
|
f = (int)f;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
/* TODO? scalers and stuff, need to review */
|
2003-01-26 19:07:53 +00:00
|
|
|
ftmatrix.xx = matrix[0] / f * 65536.0;
|
|
|
|
ftmatrix.xy = matrix[1] / f * 65536.0;
|
|
|
|
ftmatrix.yx = matrix[2] / f * 65536.0;
|
|
|
|
ftmatrix.yy = matrix[3] / f * 65536.0;
|
|
|
|
ftdelta.x = ftdelta.y = 0;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
if (FTC_Manager_LookupSize(ftc_manager, &scaler, &size))
|
2009-01-04 15:56:09 +00:00
|
|
|
return NSZeroSize;
|
2005-01-11 15:02:29 +00:00
|
|
|
face = size->face;
|
2003-01-26 19:07:53 +00:00
|
|
|
|
|
|
|
if (FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP))
|
2009-01-04 15:56:09 +00:00
|
|
|
return NSZeroSize;
|
2003-01-26 19:07:53 +00:00
|
|
|
|
|
|
|
if (FT_Get_Glyph(face->glyph, &gl))
|
2009-01-04 15:56:09 +00:00
|
|
|
return NSZeroSize;
|
2003-01-26 19:07:53 +00:00
|
|
|
|
|
|
|
if (FT_Glyph_Transform(gl, &ftmatrix, &ftdelta))
|
2009-01-04 15:56:09 +00:00
|
|
|
return NSZeroSize;
|
2003-01-26 19:07:53 +00:00
|
|
|
|
|
|
|
s = NSMakeSize(gl->advance.x / 65536.0, gl->advance.y / 65536.0);
|
|
|
|
|
|
|
|
FT_Done_Glyph(gl);
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
2003-01-26 19:07:53 +00:00
|
|
|
- (NSRect) boundingRectForGlyph: (NSGlyph)glyph
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2002-08-21 13:02:26 +00:00
|
|
|
FT_BBox bbox;
|
|
|
|
FT_Glyph g;
|
2003-05-11 17:23:43 +00:00
|
|
|
FT_Error error;
|
2002-08-21 13:02:26 +00:00
|
|
|
|
2003-03-03 19:06:55 +00:00
|
|
|
glyph--;
|
2003-01-26 19:07:53 +00:00
|
|
|
/* TODO: this is ugly */
|
2005-01-11 15:02:29 +00:00
|
|
|
if ((error=FTC_ImageCache_Lookup(ftc_imagecache, &imageType, glyph, &g, NULL)))
|
2002-08-21 13:02:26 +00:00
|
|
|
{
|
2003-05-11 17:23:43 +00:00
|
|
|
NSLog(@"FTC_ImageCache_Lookup() failed with error %08x",error);
|
2009-01-04 15:56:09 +00:00
|
|
|
// NSLog(@"boundingRectForGlyph: %04x -> %i", aGlyph, glyph);
|
2002-08-21 13:02:26 +00:00
|
|
|
return fontBBox;
|
|
|
|
}
|
|
|
|
|
|
|
|
FT_Glyph_Get_CBox(g, ft_glyph_bbox_gridfit, &bbox);
|
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
/* printf("got cbox for %04x: %i, %i - %i, %i",
|
|
|
|
aGlyph, bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax);*/
|
2002-08-21 13:02:26 +00:00
|
|
|
|
|
|
|
return NSMakeRect(bbox.xMin / 64.0, bbox.yMin / 64.0,
|
2009-01-04 15:56:09 +00:00
|
|
|
(bbox.xMax - bbox.xMin) / 64.0, (bbox.yMax - bbox.yMin) / 64.0);
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
2006-07-04 21:54:48 +00:00
|
|
|
- (NSPoint) positionOfGlyph: (NSGlyph)g
|
2009-01-04 15:56:09 +00:00
|
|
|
precededByGlyph: (NSGlyph)prev
|
|
|
|
isNominal: (BOOL *)nominal
|
2003-01-26 19:07:53 +00:00
|
|
|
{
|
|
|
|
NSPoint a;
|
|
|
|
FT_Face face;
|
2005-01-11 15:02:29 +00:00
|
|
|
FT_Size size;
|
2003-01-26 19:07:53 +00:00
|
|
|
FT_Vector vec;
|
|
|
|
FT_GlyphSlot glyph;
|
|
|
|
|
|
|
|
if (nominal)
|
|
|
|
*nominal = YES;
|
|
|
|
|
|
|
|
if (g == NSControlGlyph || prev == NSControlGlyph)
|
|
|
|
return NSZeroPoint;
|
|
|
|
|
2004-05-13 15:14:46 +00:00
|
|
|
g--;
|
|
|
|
prev--;
|
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
if (FTC_Manager_LookupSize(ftc_manager, &scaler, &size))
|
2003-01-26 19:07:53 +00:00
|
|
|
return NSZeroPoint;
|
2005-01-11 15:02:29 +00:00
|
|
|
face = size->face;
|
2003-01-26 19:07:53 +00:00
|
|
|
|
|
|
|
if (FT_Load_Glyph(face, prev, FT_LOAD_DEFAULT))
|
|
|
|
return NSZeroPoint;
|
|
|
|
|
|
|
|
glyph = face->glyph;
|
|
|
|
a = NSMakePoint(glyph->advance.x / 64.0, glyph->advance.y / 64.0);
|
|
|
|
|
|
|
|
if (FT_Get_Kerning(face, prev, g, ft_kerning_default, &vec))
|
|
|
|
return a;
|
|
|
|
|
|
|
|
if (vec.x == 0 && vec.y == 0)
|
|
|
|
return a;
|
|
|
|
|
|
|
|
if (nominal)
|
|
|
|
*nominal = NO;
|
|
|
|
|
|
|
|
a.x += vec.x / 64.0;
|
|
|
|
a.y += vec.y / 64.0;
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-20 16:33:30 +00:00
|
|
|
- (CGFloat) widthOfString: (NSString*)string
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2002-08-21 13:02:26 +00:00
|
|
|
unichar ch;
|
|
|
|
int i, c = [string length];
|
|
|
|
int total;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
unsigned int glyph;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
FTC_SBit sbit;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
total = 0;
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
ch = [string characterAtIndex: i];
|
2005-01-11 15:02:29 +00:00
|
|
|
glyph = FTC_CMapCache_Lookup(ftc_cmapcache, faceId, unicodeCmap, ch);
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
/* TODO: shouldn't use sbit cache for this */
|
|
|
|
if (1)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
if (FTC_SBitCache_Lookup(ftc_sbitcache, &imageType, glyph, &sbit, NULL))
|
|
|
|
continue;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
total += sbit->xadvance;
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
else
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
NSLog(@"non-sbit code not implemented");
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
}
|
|
|
|
return total;
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-07-04 21:54:48 +00:00
|
|
|
- (NSGlyph) glyphWithName: (NSString *)glyphName
|
2003-06-11 13:33:34 +00:00
|
|
|
{
|
|
|
|
FT_Face face;
|
2005-01-11 15:02:29 +00:00
|
|
|
FT_Size size;
|
2003-06-11 13:33:34 +00:00
|
|
|
NSGlyph g;
|
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
if (FTC_Manager_LookupSize(ftc_manager, &scaler, &size))
|
2003-06-11 13:33:34 +00:00
|
|
|
return NSNullGlyph;
|
2005-01-11 15:02:29 +00:00
|
|
|
face = size->face;
|
2003-06-11 13:33:34 +00:00
|
|
|
|
|
|
|
g = FT_Get_Name_Index(face, (FT_String *)[glyphName lossyCString]);
|
|
|
|
if (g)
|
|
|
|
return g + 1;
|
|
|
|
|
|
|
|
return NSNullGlyph;
|
|
|
|
}
|
|
|
|
|
2002-08-20 16:36:09 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
conic: (a,b,c)
|
|
|
|
p=(1-t)^2*a + 2*(1-t)*t*b + t^2*c
|
|
|
|
|
|
|
|
cubic: (a,b,c,d)
|
|
|
|
p=(1-t)^3*a + 3*(1-t)^2*t*b + 3*(1-t)*t^2*c + t^3*d
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
p(t)=(1-t)^3*a + 3*(1-t)^2*t*b + 3*(1-t)*t^2*c + t^3*d
|
|
|
|
t=m+ns=
|
|
|
|
n=l-m
|
|
|
|
|
|
|
|
|
|
|
|
q(s)=p(m+ns)=
|
|
|
|
|
|
|
|
(d-3c+3b-a)*n^3 * s^3 +
|
|
|
|
((3d-9c+9b-3a)*m+3c-6b+3a)*n^2 * s^2 +
|
|
|
|
((3d-9c+9b-3a)*m^2+(6c-12b+6a)*m+3b-3a)*n * s +
|
|
|
|
(d-3c+3b-a)*m^3+(3c-6b+3a)*m^2+(3b-3a)m+a
|
|
|
|
|
|
|
|
|
|
|
|
q(t)=(1-t)^3*aa + 3*(1-t)^2*t*bb + 3*(1-t)*t^2*cc + t^3*dd =
|
|
|
|
|
|
|
|
(dd-3cc+3bb-aa)*t^3 +
|
|
|
|
(3cc-6bb+3aa)*t^2 +
|
|
|
|
(3bb-3aa)*t +
|
|
|
|
aa
|
|
|
|
|
|
|
|
|
|
|
|
aa = (d-3*c+3*b-a)*m^3+(3*c-6*b+3*a)*m^2+(3*b-3*a)*m+a
|
|
|
|
3*bb-3*aa = ((3*d-9*c+9*b-3*a)*m^2+(6*c-12*b+6*a)*m+3*b-3*a)*n
|
|
|
|
3*cc-6*bb+3*aa = ((3*d-9*c+9*b-3*a)*m+3*c-6*b+3*a)*n^2
|
|
|
|
dd-3*cc+3*bb-aa = (d-3*c+3*b-a)*n^3
|
|
|
|
|
|
|
|
|
|
|
|
aa= (d - 3c + 3b - a) m^3 + (3c - 6b + 3a) m^2 + (3b - 3a) m + a
|
|
|
|
|
2005-11-16 11:40:31 +00:00
|
|
|
bb= ((d - 3c + 3b - a) m^2 + (2c - 4b + 2a) m + b - a) n
|
2002-08-20 16:36:09 +00:00
|
|
|
+ aa
|
|
|
|
|
|
|
|
cc= ((d - 3c + 3b - a) m + c - 2b + a) n^2
|
|
|
|
+ 2*bb
|
|
|
|
+ aa
|
|
|
|
|
|
|
|
dd= (d - 3c + 3b - a) n^3
|
|
|
|
+ 3*cc
|
|
|
|
+ 3*bb
|
|
|
|
+ aa
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
p(t) = (1-t)^2*e + 2*(1-t)*t*f + t^2*g
|
|
|
|
~=
|
|
|
|
q(t) = (1-t)^3*a + 3*(1-t)^2*t*b + 3*(1-t)*t^2*c + t^3*d
|
|
|
|
|
|
|
|
|
|
|
|
p(0)=q(0) && p(1)=q(1) ->
|
|
|
|
a=e
|
|
|
|
d=g
|
|
|
|
|
|
|
|
|
|
|
|
p(0.5) = 1/8*(2a + 4f + 2d)
|
|
|
|
q(0.5) = 1/8*(a + 3*b + 3*c + d)
|
|
|
|
|
|
|
|
b+c=1/3*(a+4f+d)
|
|
|
|
|
|
|
|
p(1/4) = 1/64*
|
2005-11-16 11:40:31 +00:00
|
|
|
p(3/4) = 1/64*(4e+24f+36g)
|
2002-08-20 16:36:09 +00:00
|
|
|
|
|
|
|
q(1/4) = 1/64*
|
2005-11-16 11:40:31 +00:00
|
|
|
q(3/4) = 1/64*(a + 9b + 27c + 27d)
|
2002-08-20 16:36:09 +00:00
|
|
|
|
|
|
|
3b+c=1/3*(3a+8f+d)
|
|
|
|
|
|
|
|
|
|
|
|
3b+c=1/3*(3a+8f+d)
|
|
|
|
b+c=1/3*(a+4f+d)
|
|
|
|
|
|
|
|
b=1/3*(e+2f)
|
|
|
|
c=1/3*(2f+g)
|
|
|
|
|
|
|
|
|
|
|
|
q(t) = (1-t)^3*e + (1-t)^2*t*(e+2f) + (1-t)*t^2*(2f+g) + t^3*g =
|
|
|
|
((1-t)^3+(1-t)^2*t)*e + (1-t)^2*t*2f + (1-t)*t^2*2f + (t^3+(1-t)*t^2)*g =
|
|
|
|
|
2005-11-16 11:40:31 +00:00
|
|
|
((1-t)^3+(1-t)^2*t)*e + 2f*(t*(1-t)*((1-t)+t)) + (t^3+(1-t)*t^2)*g =
|
2002-08-20 16:36:09 +00:00
|
|
|
((1-t)^3+(1-t)^2*t)*e + 2*(1-t)*t*f + (t^3+(1-t)*t^2)*g =
|
|
|
|
(1-t)^2*e + 2*(1-t)*t*f + t^2*g
|
|
|
|
|
|
|
|
p(t)=q(t)
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2003-06-11 13:33:34 +00:00
|
|
|
/* TODO: try to combine charpath and NSBezierPath handling? */
|
2009-01-13 00:34:14 +00:00
|
|
|
#if 0
|
2007-08-07 16:04:47 +00:00
|
|
|
static int charpath_move_to(const FT_Vector *to, void *user)
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2002-08-21 13:02:26 +00:00
|
|
|
GSGState *self = (GSGState *)user;
|
|
|
|
NSPoint d;
|
|
|
|
d.x = to->x / 65536.0;
|
|
|
|
d.y = to->y / 65536.0;
|
|
|
|
[self DPSclosepath]; /* TODO: this isn't completely correct */
|
|
|
|
[self DPSmoveto: d.x:d.y];
|
|
|
|
return 0;
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
2007-08-07 16:04:47 +00:00
|
|
|
static int charpath_line_to(const FT_Vector *to, void *user)
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2002-08-21 13:02:26 +00:00
|
|
|
GSGState *self = (GSGState *)user;
|
|
|
|
NSPoint d;
|
|
|
|
d.x = to->x / 65536.0;
|
|
|
|
d.y = to->y / 65536.0;
|
|
|
|
[self DPSlineto: d.x:d.y];
|
|
|
|
return 0;
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
2007-08-07 16:04:47 +00:00
|
|
|
static int charpath_conic_to(const FT_Vector *c1, const FT_Vector *to, void *user)
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2002-08-21 13:02:26 +00:00
|
|
|
GSGState *self = (GSGState *)user;
|
|
|
|
NSPoint a, b, c, d;
|
|
|
|
[self DPScurrentpoint: &a.x:&a.y];
|
|
|
|
d.x = to->x / 65536.0;
|
|
|
|
d.y = to->y / 65536.0;
|
|
|
|
b.x = c1->x / 65536.0;
|
|
|
|
b.y = c1->y / 65536.0;
|
|
|
|
c.x = (b.x * 2 + d.x) / 3.0;
|
|
|
|
c.y = (b.y * 2 + d.y) / 3.0;
|
|
|
|
b.x = (b.x * 2 + a.x) / 3.0;
|
|
|
|
b.y = (b.y * 2 + a.y) / 3.0;
|
|
|
|
[self DPScurveto: b.x:b.y : c.x:c.y : d.x:d.y];
|
|
|
|
return 0;
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
2007-08-07 16:04:47 +00:00
|
|
|
static int charpath_cubic_to(const FT_Vector *c1, const FT_Vector *c2,
|
|
|
|
const FT_Vector *to, void *user)
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2002-08-21 13:02:26 +00:00
|
|
|
GSGState *self = (GSGState *)user;
|
|
|
|
NSPoint b, c, d;
|
|
|
|
b.x = c1->x / 65536.0;
|
|
|
|
b.y = c1->y / 65536.0;
|
|
|
|
c.x = c2->x / 65536.0;
|
|
|
|
c.y = c2->y / 65536.0;
|
|
|
|
d.x = to->x / 65536.0;
|
|
|
|
d.y = to->y / 65536.0;
|
|
|
|
[self DPScurveto: b.x:b.y : c.x:c.y : d.x:d.y];
|
|
|
|
return 0;
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
2003-06-11 13:33:34 +00:00
|
|
|
static FT_Outline_Funcs charpath_funcs = {
|
2006-07-04 21:54:48 +00:00
|
|
|
move_to:charpath_move_to,
|
|
|
|
line_to:charpath_line_to,
|
|
|
|
conic_to:charpath_conic_to,
|
|
|
|
cubic_to:charpath_cubic_to,
|
|
|
|
shift:10,
|
|
|
|
delta:0,
|
2002-08-20 16:36:09 +00:00
|
|
|
};
|
2009-01-13 00:34:14 +00:00
|
|
|
#endif
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2007-08-07 16:04:47 +00:00
|
|
|
static int bezierpath_move_to(const FT_Vector *to, void *user)
|
2003-06-11 13:33:34 +00:00
|
|
|
{
|
|
|
|
NSBezierPath *path = (NSBezierPath *)user;
|
|
|
|
NSPoint d;
|
|
|
|
d.x = to->x / 65536.0;
|
|
|
|
d.y = to->y / 65536.0;
|
|
|
|
[path closePath]; /* TODO: this isn't completely correct */
|
|
|
|
[path moveToPoint: d];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-07 16:04:47 +00:00
|
|
|
static int bezierpath_line_to(const FT_Vector *to, void *user)
|
2003-06-11 13:33:34 +00:00
|
|
|
{
|
|
|
|
NSBezierPath *path = (NSBezierPath *)user;
|
|
|
|
NSPoint d;
|
|
|
|
d.x = to->x / 65536.0;
|
|
|
|
d.y = to->y / 65536.0;
|
|
|
|
[path lineToPoint: d];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-07 16:04:47 +00:00
|
|
|
static int bezierpath_conic_to(const FT_Vector *c1, const FT_Vector *to, void *user)
|
2003-06-11 13:33:34 +00:00
|
|
|
{
|
|
|
|
NSBezierPath *path = (NSBezierPath *)user;
|
|
|
|
NSPoint a, b, c, d;
|
|
|
|
a = [path currentPoint];
|
|
|
|
d.x = to->x / 65536.0;
|
|
|
|
d.y = to->y / 65536.0;
|
|
|
|
b.x = c1->x / 65536.0;
|
|
|
|
b.y = c1->y / 65536.0;
|
|
|
|
c.x = (b.x * 2 + d.x) / 3.0;
|
|
|
|
c.y = (b.y * 2 + d.y) / 3.0;
|
|
|
|
b.x = (b.x * 2 + a.x) / 3.0;
|
|
|
|
b.y = (b.y * 2 + a.y) / 3.0;
|
|
|
|
[path curveToPoint: d controlPoint1: b controlPoint2: c];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-07 16:04:47 +00:00
|
|
|
static int bezierpath_cubic_to(const FT_Vector *c1, const FT_Vector *c2,
|
|
|
|
const FT_Vector *to, void *user)
|
2003-06-11 13:33:34 +00:00
|
|
|
{
|
|
|
|
NSBezierPath *path = (NSBezierPath *)user;
|
|
|
|
NSPoint b, c, d;
|
|
|
|
b.x = c1->x / 65536.0;
|
|
|
|
b.y = c1->y / 65536.0;
|
|
|
|
c.x = c2->x / 65536.0;
|
|
|
|
c.y = c2->y / 65536.0;
|
|
|
|
d.x = to->x / 65536.0;
|
|
|
|
d.y = to->y / 65536.0;
|
|
|
|
[path curveToPoint: d controlPoint1: b controlPoint2: c];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static FT_Outline_Funcs bezierpath_funcs = {
|
2020-01-17 15:23:07 +00:00
|
|
|
.move_to = bezierpath_move_to,
|
|
|
|
.line_to = bezierpath_line_to,
|
|
|
|
.conic_to = bezierpath_conic_to,
|
|
|
|
.cubic_to = bezierpath_cubic_to,
|
|
|
|
.shift = 10,
|
|
|
|
.delta = 0,
|
2003-06-11 13:33:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2002-08-20 16:36:09 +00:00
|
|
|
/* TODO: sometimes gets 'glyph transformation failed', probably need to
|
|
|
|
add code to avoid loading bitmaps for glyphs */
|
2006-07-04 21:54:48 +00:00
|
|
|
- (void) outlineString: (const char *)s
|
2013-02-05 19:18:49 +00:00
|
|
|
at: (CGFloat)x : (CGFloat)y
|
2009-01-04 15:56:09 +00:00
|
|
|
gstate: (void *)func_param
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2005-01-11 15:02:29 +00:00
|
|
|
#if 0
|
2002-08-21 13:02:26 +00:00
|
|
|
unichar *c;
|
|
|
|
int i;
|
|
|
|
FTC_CMapDescRec cmap;
|
|
|
|
unsigned int glyph;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
unichar *uch;
|
|
|
|
int ulen;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-06-07 21:06:19 +00:00
|
|
|
FTC_ImageTypeRec cur;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
FT_Matrix ftmatrix;
|
|
|
|
FT_Vector ftdelta;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
ftmatrix.xx = 65536;
|
|
|
|
ftmatrix.xy = 0;
|
|
|
|
ftmatrix.yx = 0;
|
|
|
|
ftmatrix.yy = 65536;
|
|
|
|
ftdelta.x = x * 64.0;
|
|
|
|
ftdelta.y = y * 64.0;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
uch = NULL;
|
|
|
|
ulen = 0;
|
|
|
|
GSToUnicode(&uch, &ulen, s, strlen(s), NSUTF8StringEncoding, NSDefaultMallocZone(), 0);
|
2002-08-20 16:36:09 +00:00
|
|
|
|
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
cur = imgd;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
cmap.face_id = imgd.font.face_id;
|
|
|
|
cmap.u.encoding = ft_encoding_unicode;
|
|
|
|
cmap.type = FTC_CMAP_BY_ENCODING;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
for (c = uch, i = 0; i < ulen; i++, c++)
|
|
|
|
{
|
|
|
|
FT_Face face;
|
|
|
|
FT_Glyph gl;
|
|
|
|
FT_OutlineGlyph og;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
glyph = FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, *c);
|
|
|
|
cur.font.face_id = imgd.font.face_id;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
if (FTC_Manager_Lookup_Size(ftc_manager, &cur.font, &face, 0))
|
2009-01-04 15:56:09 +00:00
|
|
|
continue;
|
2002-08-21 13:02:26 +00:00
|
|
|
if (FT_Load_Glyph(face, glyph, FT_LOAD_DEFAULT))
|
2009-01-04 15:56:09 +00:00
|
|
|
continue;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
if (FT_Get_Glyph(face->glyph, &gl))
|
2009-01-04 15:56:09 +00:00
|
|
|
continue;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
if (FT_Glyph_Transform(gl, &ftmatrix, &ftdelta))
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
NSLog(@"glyph transformation failed!");
|
|
|
|
continue;
|
|
|
|
}
|
2002-08-21 13:02:26 +00:00
|
|
|
og = (FT_OutlineGlyph)gl;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
ftdelta.x += gl->advance.x >> 10;
|
|
|
|
ftdelta.y += gl->advance.y >> 10;
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-06-11 13:33:34 +00:00
|
|
|
FT_Outline_Decompose(&og->outline, &charpath_funcs, func_param);
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
FT_Done_Glyph(gl);
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2003-06-11 13:33:34 +00:00
|
|
|
if (ulen)
|
|
|
|
{
|
|
|
|
[(GSGState *)func_param DPSmoveto: ftdelta.x / 64.0 : ftdelta.y / 64.0];
|
|
|
|
}
|
|
|
|
|
2002-08-21 13:02:26 +00:00
|
|
|
free(uch);
|
2005-01-11 15:02:29 +00:00
|
|
|
#endif
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
2006-07-04 21:54:48 +00:00
|
|
|
- (void) appendBezierPathWithGlyphs: (NSGlyph *)glyphs
|
2008-04-07 13:51:28 +00:00
|
|
|
count: (int)count
|
|
|
|
toBezierPath: (NSBezierPath *)path
|
2003-06-11 13:33:34 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
NSGlyph glyph;
|
|
|
|
|
|
|
|
FT_Matrix ftmatrix;
|
|
|
|
FT_Vector ftdelta;
|
|
|
|
|
|
|
|
NSPoint p = [path currentPoint];
|
|
|
|
|
|
|
|
ftmatrix.xx = 65536;
|
|
|
|
ftmatrix.xy = 0;
|
|
|
|
ftmatrix.yx = 0;
|
|
|
|
ftmatrix.yy = 65536;
|
|
|
|
ftdelta.x = p.x * 64.0;
|
|
|
|
ftdelta.y = p.y * 64.0;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++, glyphs++)
|
|
|
|
{
|
|
|
|
FT_Face face;
|
|
|
|
FT_Glyph gl;
|
|
|
|
FT_OutlineGlyph og;
|
2006-11-25 21:45:06 +00:00
|
|
|
FT_Size size;
|
2003-06-11 13:33:34 +00:00
|
|
|
|
|
|
|
glyph = *glyphs - 1;
|
|
|
|
|
2006-11-25 21:45:06 +00:00
|
|
|
if (FTC_Manager_LookupSize(ftc_manager, &scaler, &size))
|
2009-01-04 15:56:09 +00:00
|
|
|
continue;
|
2006-11-25 21:45:06 +00:00
|
|
|
|
|
|
|
face = size->face;
|
|
|
|
|
2003-06-11 13:33:34 +00:00
|
|
|
if (FT_Load_Glyph(face, glyph, FT_LOAD_DEFAULT))
|
2009-01-04 15:56:09 +00:00
|
|
|
continue;
|
2003-06-11 13:33:34 +00:00
|
|
|
|
|
|
|
if (FT_Get_Glyph(face->glyph, &gl))
|
2009-01-04 15:56:09 +00:00
|
|
|
continue;
|
2003-06-11 13:33:34 +00:00
|
|
|
|
|
|
|
if (FT_Glyph_Transform(gl, &ftmatrix, &ftdelta))
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
NSLog(@"glyph transformation failed!");
|
|
|
|
continue;
|
|
|
|
}
|
2003-06-11 13:33:34 +00:00
|
|
|
og = (FT_OutlineGlyph)gl;
|
|
|
|
|
|
|
|
ftdelta.x += gl->advance.x >> 10;
|
|
|
|
ftdelta.y += gl->advance.y >> 10;
|
|
|
|
|
|
|
|
FT_Outline_Decompose(&og->outline, &bezierpath_funcs, path);
|
|
|
|
|
|
|
|
FT_Done_Glyph(gl);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count)
|
|
|
|
{
|
|
|
|
[path moveToPoint: NSMakePoint(ftdelta.x / 64.0, ftdelta.y / 64.0)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-08-28 11:31:58 +00:00
|
|
|
static int filters[3][7]=
|
|
|
|
{
|
|
|
|
{ 0*65536/9, 1*65536/9, 2*65536/9, 3*65536/9, 2*65536/9, 1*65536/9, 0*65536/9},
|
|
|
|
{ 0*65536/9, 1*65536/9, 2*65536/9, 3*65536/9, 2*65536/9, 1*65536/9, 0*65536/9},
|
|
|
|
{ 0*65536/9, 1*65536/9, 2*65536/9, 3*65536/9, 2*65536/9, 1*65536/9, 0*65536/9}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2007-01-31 15:52:53 +00:00
|
|
|
+ (void) initializeBackend
|
2002-08-20 16:36:09 +00:00
|
|
|
{
|
2002-08-21 13:02:26 +00:00
|
|
|
[GSFontEnumerator setDefaultClass: [FTFontEnumerator class]];
|
|
|
|
[GSFontInfo setDefaultClass: [FTFontInfo class]];
|
|
|
|
|
|
|
|
if (FT_Init_FreeType(&ft_library))
|
|
|
|
NSLog(@"FT_Init_FreeType failed");
|
|
|
|
if (FTC_Manager_New(ft_library, 0, 0, 4096 * 24, ft_get_face, 0, &ftc_manager))
|
|
|
|
NSLog(@"FTC_Manager_New failed");
|
|
|
|
if (FTC_SBitCache_New(ftc_manager, &ftc_sbitcache))
|
|
|
|
NSLog(@"FTC_SBitCache_New failed");
|
|
|
|
if (FTC_ImageCache_New(ftc_manager, &ftc_imagecache))
|
|
|
|
NSLog(@"FTC_ImageCache_New failed");
|
|
|
|
if (FTC_CMapCache_New(ftc_manager, &ftc_cmapcache))
|
|
|
|
NSLog(@"FTC_CMapCache_New failed");
|
|
|
|
|
2002-08-28 11:31:58 +00:00
|
|
|
{
|
|
|
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
|
|
|
NSString *s;
|
|
|
|
NSArray *a;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
subpixel_text = [ud integerForKey: @"back-art-subpixel-text"];
|
|
|
|
|
|
|
|
/* To make it easier to find an optimal (or at least good) filter,
|
|
|
|
the filters are configurable (for now). */
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
s = [ud stringForKey:
|
|
|
|
[NSString stringWithFormat: @"back-art-subpixel-filter-%i",i]];
|
|
|
|
if (s)
|
|
|
|
{
|
|
|
|
int j, c, sum, v;
|
|
|
|
a = [s componentsSeparatedByString: @" "];
|
|
|
|
c = [a count];
|
|
|
|
if (!c)
|
|
|
|
continue;
|
|
|
|
if (!(c & 1) || c > 7)
|
|
|
|
{
|
|
|
|
NSLog(@"invalid number of components in filter (must be odd number, 1<=n<=7)");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
memset(filters[i], 0, sizeof(filters[0]));
|
|
|
|
sum = 0;
|
|
|
|
for (j = 0; j < c; j++)
|
|
|
|
{
|
|
|
|
v = [[a objectAtIndex: j] intValue];
|
|
|
|
sum += v;
|
|
|
|
filters[i][j + (7 - c) / 2] = v * 65536;
|
|
|
|
}
|
|
|
|
if (sum)
|
|
|
|
{
|
|
|
|
for (j = 0; j < 7; j++)
|
|
|
|
{
|
|
|
|
filters[i][j] /= sum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NSLog(@"filter %i: %04x %04x %04x %04x %04x %04x %04x",
|
|
|
|
i,
|
|
|
|
filters[i][0],filters[i][1],filters[i][2],filters[i][3],
|
|
|
|
filters[i][4],filters[i][5],filters[i][6]);
|
|
|
|
}
|
2002-08-28 11:31:58 +00:00
|
|
|
}
|
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
}
|
|
|
|
|
2008-04-04 22:07:03 +00:00
|
|
|
- (NSGlyph) glyphForCharacter: (unichar)ch
|
|
|
|
{
|
|
|
|
NSGlyph g;
|
|
|
|
|
|
|
|
g = FTC_CMapCache_Lookup(ftc_cmapcache, faceId, unicodeCmap, ch);
|
|
|
|
if (g)
|
|
|
|
return g + 1;
|
|
|
|
else
|
|
|
|
return NSNullGlyph;
|
|
|
|
}
|
2002-08-20 16:36:09 +00:00
|
|
|
|
2008-04-07 13:51:28 +00:00
|
|
|
- (NSMultibyteGlyphPacking) glyphPacking
|
|
|
|
{
|
|
|
|
return NSFourByteGlyphPacking;
|
|
|
|
}
|
|
|
|
|
2002-08-20 16:36:09 +00:00
|
|
|
@end
|
|
|
|
|
2002-08-27 09:59:22 +00:00
|
|
|
|
2003-01-26 19:07:53 +00:00
|
|
|
/* TODO: this whole thing needs cleaning up */
|
2002-08-27 09:59:22 +00:00
|
|
|
@implementation FTFontInfo_subpixel
|
|
|
|
|
2005-01-11 15:02:29 +00:00
|
|
|
#if 0
|
2006-07-04 21:54:48 +00:00
|
|
|
- (void) drawGlyphs: (const NSGlyph *)glyphs : (int)length
|
2009-01-04 15:56:09 +00:00
|
|
|
at: (int)x : (int)y
|
|
|
|
to: (int)x0 : (int)y0 : (int)x1 : (int)y1
|
|
|
|
: (unsigned char *)buf : (int)bpl
|
|
|
|
color: (unsigned char)r : (unsigned char)g : (unsigned char)b
|
|
|
|
: (unsigned char)alpha
|
|
|
|
transform: (NSAffineTransform *)transform
|
|
|
|
drawinfo: (struct draw_info_s *)di
|
2002-08-27 09:59:22 +00:00
|
|
|
{
|
|
|
|
FTC_CMapDescRec cmap;
|
|
|
|
unsigned int glyph;
|
|
|
|
|
|
|
|
int use_sbit;
|
|
|
|
|
|
|
|
FTC_SBit sbit;
|
2003-06-07 21:06:19 +00:00
|
|
|
FTC_ImageTypeRec cur;
|
2002-08-27 09:59:22 +00:00
|
|
|
|
|
|
|
FT_Matrix ftmatrix;
|
|
|
|
FT_Vector ftdelta;
|
2009-01-04 15:56:09 +00:00
|
|
|
NSAffineTransformStruct ts;
|
2002-08-27 09:59:22 +00:00
|
|
|
|
|
|
|
BOOL subpixel = NO;
|
|
|
|
|
|
|
|
if (!alpha)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* TODO: if we had guaranteed upper bounds on glyph image size we
|
|
|
|
could do some basic clipping here */
|
|
|
|
|
|
|
|
x1 -= x0;
|
|
|
|
y1 -= y0;
|
|
|
|
x -= x0;
|
|
|
|
y -= y0;
|
|
|
|
|
2006-11-19 11:08:09 +00:00
|
|
|
ts = [transform transformStruct];
|
2002-08-27 09:59:22 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
/* NSLog(@"[%@ draw using matrix: (%g %g %g %g %g %g)]",
|
|
|
|
self,
|
|
|
|
matrix[0], matrix[1], matrix[2],
|
|
|
|
matrix[3], matrix[4], matrix[5]
|
|
|
|
);*/
|
2002-08-27 09:59:22 +00:00
|
|
|
|
|
|
|
cur = imgd;
|
|
|
|
{
|
|
|
|
float xx, xy, yx, yy;
|
|
|
|
|
2006-11-19 11:08:09 +00:00
|
|
|
xx = matrix[0] * ts.m11 + matrix[1] * ts.m21;
|
|
|
|
yx = matrix[0] * ts.m12 + matrix[1] * ts.m22;
|
|
|
|
xy = matrix[2] * ts.m11 + matrix[3] * ts.m21;
|
|
|
|
yy = matrix[2] * ts.m12 + matrix[3] * ts.m22;
|
2002-08-27 09:59:22 +00:00
|
|
|
|
|
|
|
/* if we're drawing 'normal' text (unscaled, unrotated, reasonable
|
|
|
|
size), we can and should use the sbit cache */
|
2006-11-19 11:08:09 +00:00
|
|
|
if (fabs(xx - ((int)xx)) < 0.01 && fabs(yy - ((int)yy)) < 0.01
|
|
|
|
&& fabs(xy) < 0.01 && fabs(yx) < 0.01
|
|
|
|
&& xx < 72 && yy < 72 && xx > 0.5 && yy > 0.5)
|
2002-08-27 09:59:22 +00:00
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
use_sbit = 1;
|
|
|
|
cur.font.pix_width = xx;
|
|
|
|
cur.font.pix_height = yy;
|
|
|
|
|
|
|
|
/* if (cur.font.pix_width < 16 && cur.font.pix_height < 16 &&
|
|
|
|
cur.font.pix_width > 6 && cur.font.pix_height > 6)
|
|
|
|
cur.type = ftc_image_mono;
|
|
|
|
else*/
|
|
|
|
cur.flags = FT_LOAD_TARGET_LCD, subpixel = YES;
|
|
|
|
// imgd.type|=|ftc_image_flag_unhinted; /* TODO? when? */
|
2002-08-27 09:59:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-01-04 15:56:09 +00:00
|
|
|
float f;
|
|
|
|
use_sbit = 0;
|
|
|
|
|
|
|
|
f = fabs(xx * yy - xy * yx);
|
|
|
|
if (f > 1)
|
|
|
|
f = sqrt(f);
|
|
|
|
else
|
|
|
|
f = 1.0;
|
|
|
|
|
|
|
|
f = (int)f;
|
|
|
|
|
|
|
|
cur.font.pix_width = cur.font.pix_height = f;
|
|
|
|
ftmatrix.xx = xx / f * 65536.0;
|
|
|
|
ftmatrix.xy = xy / f * 65536.0;
|
|
|
|
ftmatrix.yx = yx / f * 65536.0;
|
|
|
|
ftmatrix.yy = yy / f * 65536.0;
|
|
|
|
ftdelta.x = ftdelta.y = 0;
|
2002-08-27 09:59:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
/* NSLog(@"drawString: '%s' at: %i:%i to: %i:%i:%i:%i:%p",
|
|
|
|
s, x, y, x0, y0, x1, y1, buf);*/
|
2002-08-27 09:59:22 +00:00
|
|
|
|
|
|
|
cmap.face_id = imgd.font.face_id;
|
|
|
|
cmap.u.encoding = ft_encoding_unicode;
|
|
|
|
cmap.type = FTC_CMAP_BY_ENCODING;
|
|
|
|
|
2003-03-29 18:16:40 +00:00
|
|
|
for (; length; length--, glyphs++)
|
2002-08-27 09:59:22 +00:00
|
|
|
{
|
2003-03-29 18:16:40 +00:00
|
|
|
glyph = *glyphs - 1;
|
2002-08-27 09:59:22 +00:00
|
|
|
|
|
|
|
if (use_sbit)
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
if (FTC_SBitCache_Lookup(ftc_sbitcache, &cur, glyph, &sbit, NULL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!sbit->buffer)
|
|
|
|
{
|
|
|
|
x += sbit->xadvance;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sbit->format == FT_PIXEL_MODE_LCD)
|
|
|
|
{
|
|
|
|
int gx = 3 * x + sbit->left, gy = y - sbit->top;
|
|
|
|
int px0 = (gx - 2 < 0? gx - 4 : gx - 2) / 3;
|
|
|
|
int px1 = (gx + sbit->width + 2 < 0? gx + sbit->width + 2: gx + sbit->width + 4) / 3;
|
|
|
|
int llip = gx - px0 * 3;
|
|
|
|
int sbpl = sbit->pitch;
|
|
|
|
int sx = sbit->width, sy = sbit->height;
|
|
|
|
int psx = px1 - px0;
|
|
|
|
const unsigned char *src = sbit->buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
unsigned char scratch[psx * 3];
|
|
|
|
int mode = subpixel_text == 2? 2 : 0;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (px1 > x1)
|
|
|
|
px1 = x1;
|
|
|
|
if (px0 < 0)
|
|
|
|
{
|
|
|
|
px0 = -px0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
px1 -= px0;
|
|
|
|
dst += px0 * DI.bytes_per_pixel;
|
|
|
|
px0 = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (px1 <= 0)
|
|
|
|
{
|
|
|
|
x += sbit->xadvance;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
int v0, v1, v2;
|
|
|
|
for (i = 0, j = -llip; i < psx * 3; i+=3)
|
|
|
|
{
|
|
|
|
v0 = (0 +
|
|
|
|
+ (j > 2 && j<sx + 3? src[j - 3] * filters[0][0] : 0)
|
|
|
|
+ (j > 1 && j<sx + 2? src[j - 2] * filters[0][1] : 0)
|
|
|
|
+ (j > 0 && j<sx + 1? src[j - 1] * filters[0][2] : 0)
|
|
|
|
+ (j > -1 && j<sx ? src[j ] * filters[0][3] : 0)
|
|
|
|
+ (j > -2 && j<sx - 1? src[j + 1] * filters[0][4] : 0)
|
|
|
|
+ (j > -3 && j<sx - 2? src[j + 2] * filters[0][5] : 0)
|
|
|
|
+ (j > -4 && j<sx - 3? src[j + 3] * filters[0][6] : 0)
|
|
|
|
) / 65536;
|
|
|
|
j++;
|
|
|
|
v1 = (0 +
|
|
|
|
+ (j > 2 && j<sx + 3? src[j - 3] * filters[1][0] : 0)
|
|
|
|
+ (j > 1 && j<sx + 2? src[j - 2] * filters[1][1] : 0)
|
|
|
|
+ (j > 0 && j<sx + 1? src[j - 1] * filters[1][2] : 0)
|
|
|
|
+ (j > -1 && j<sx ? src[j ] * filters[1][3] : 0)
|
|
|
|
+ (j > -2 && j<sx - 1? src[j + 1] * filters[1][4] : 0)
|
|
|
|
+ (j > -3 && j<sx - 2? src[j + 2] * filters[1][5] : 0)
|
|
|
|
+ (j > -4 && j<sx - 3? src[j + 3] * filters[1][6] : 0)
|
|
|
|
) / 65536;
|
|
|
|
j++;
|
|
|
|
v2 = (0 +
|
|
|
|
+ (j > 2 && j<sx + 3? src[j - 3] * filters[2][0] : 0)
|
|
|
|
+ (j > 1 && j<sx + 2? src[j - 2] * filters[2][1] : 0)
|
|
|
|
+ (j > 0 && j<sx + 1? src[j - 1] * filters[2][2] : 0)
|
|
|
|
+ (j > -1 && j<sx ? src[j ] * filters[2][3] : 0)
|
|
|
|
+ (j > -2 && j<sx - 1? src[j + 1] * filters[2][4] : 0)
|
|
|
|
+ (j > -3 && j<sx - 2? src[j + 2] * filters[2][5] : 0)
|
|
|
|
+ (j > -4 && j<sx - 3? src[j + 3] * filters[2][6] : 0)
|
|
|
|
) / 65536;
|
|
|
|
j++;
|
|
|
|
|
|
|
|
scratch[i + mode] = v0>0?v0:0;
|
|
|
|
scratch[i + 1] = v1>0?v1:0;
|
|
|
|
scratch[i + (mode ^ 2)] = v2>0?v2:0;
|
|
|
|
}
|
|
|
|
DI.render_blit_subpixel(dst,
|
|
|
|
scratch + px0 * 3, r, g, b, alpha,
|
|
|
|
px1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (sbit->format == ft_pixel_mode_mono)
|
|
|
|
{
|
|
|
|
int gx = x + sbit->left, gy = y - sbit->top;
|
|
|
|
int sbpl = sbit->pitch;
|
|
|
|
int sx = sbit->width, sy = sbit->height;
|
|
|
|
const unsigned char *src = sbit->buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
int src_ofs = 0;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (gx < 0)
|
|
|
|
{
|
|
|
|
sx += gx;
|
|
|
|
src -= gx / 8;
|
|
|
|
src_ofs = (-gx) & 7;
|
|
|
|
gx = 0;
|
|
|
|
}
|
|
|
|
else if (gx > 0)
|
|
|
|
{
|
|
|
|
dst += DI.bytes_per_pixel * gx;
|
|
|
|
}
|
|
|
|
|
|
|
|
sx += gx;
|
|
|
|
if (sx > x1)
|
|
|
|
sx = x1;
|
|
|
|
sx -= gx;
|
|
|
|
|
|
|
|
if (sx > 0)
|
|
|
|
{
|
|
|
|
if (alpha >= 255)
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_MONO_OPAQUE(dst, src, src_ofs, r, g, b, sx);
|
|
|
|
else
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_MONO(dst, src, src_ofs, r, g, b, alpha, sx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"unhandled font bitmap format %i", sbit->format);
|
|
|
|
}
|
|
|
|
|
|
|
|
x += sbit->xadvance;
|
|
|
|
}
|
2002-08-27 09:59:22 +00:00
|
|
|
else
|
2009-01-04 15:56:09 +00:00
|
|
|
{
|
|
|
|
FT_Face face;
|
|
|
|
FT_Glyph gl;
|
|
|
|
FT_BitmapGlyph gb;
|
|
|
|
|
|
|
|
if (FTC_Manager_Lookup_Size(ftc_manager, &cur.font, &face, 0))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* TODO: for rotations of 90, 180, 270, and integer
|
|
|
|
scales hinting might still be a good idea. */
|
|
|
|
if (FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (FT_Get_Glyph(face->glyph, &gl))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (FT_Glyph_Transform(gl, &ftmatrix, &ftdelta))
|
|
|
|
{
|
|
|
|
NSLog(@"glyph transformation failed!");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (FT_Glyph_To_Bitmap(&gl, ft_render_mode_normal, 0, 1))
|
|
|
|
{
|
|
|
|
FT_Done_Glyph(gl);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
gb = (FT_BitmapGlyph)gl;
|
|
|
|
|
|
|
|
|
|
|
|
if (gb->bitmap.pixel_mode == ft_pixel_mode_grays)
|
|
|
|
{
|
|
|
|
int gx = x + gb->left, gy = y - gb->top;
|
|
|
|
int sbpl = gb->bitmap.pitch;
|
|
|
|
int sx = gb->bitmap.width, sy = gb->bitmap.rows;
|
|
|
|
const unsigned char *src = gb->bitmap.buffer;
|
|
|
|
unsigned char *dst = buf;
|
|
|
|
|
|
|
|
if (gy < 0)
|
|
|
|
{
|
|
|
|
sy += gy;
|
|
|
|
src -= sbpl * gy;
|
|
|
|
gy = 0;
|
|
|
|
}
|
|
|
|
else if (gy > 0)
|
|
|
|
{
|
|
|
|
dst += bpl * gy;
|
|
|
|
}
|
|
|
|
|
|
|
|
sy += gy;
|
|
|
|
if (sy > y1)
|
|
|
|
sy = y1;
|
|
|
|
|
|
|
|
if (gx < 0)
|
|
|
|
{
|
|
|
|
sx += gx;
|
|
|
|
src -= gx;
|
|
|
|
gx = 0;
|
|
|
|
}
|
|
|
|
else if (gx > 0)
|
|
|
|
{
|
|
|
|
dst += DI.bytes_per_pixel * gx;
|
|
|
|
}
|
|
|
|
|
|
|
|
sx += gx;
|
|
|
|
if (sx > x1)
|
|
|
|
sx = x1;
|
|
|
|
sx -= gx;
|
|
|
|
|
|
|
|
if (sx > 0)
|
|
|
|
{
|
|
|
|
if (alpha >= 255)
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_ALPHA_OPAQUE(dst, src, r, g, b, sx);
|
|
|
|
else
|
|
|
|
for (; gy < sy; gy++, src += sbpl, dst += bpl)
|
|
|
|
RENDER_BLIT_ALPHA(dst, src, r, g, b, alpha, sx);
|
|
|
|
}
|
|
|
|
}
|
2002-08-27 09:59:22 +00:00
|
|
|
/* TODO: will this case ever appear? */
|
2009-01-04 15:56:09 +00:00
|
|
|
/* else if (gb->bitmap.pixel_mode==ft_pixel_mode_mono)*/
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"unhandled font bitmap format %i", gb->bitmap.pixel_mode);
|
|
|
|
}
|
2002-08-27 09:59:22 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
ftdelta.x += gl->advance.x >> 10;
|
|
|
|
ftdelta.y += gl->advance.y >> 10;
|
2002-08-27 09:59:22 +00:00
|
|
|
|
2009-01-04 15:56:09 +00:00
|
|
|
FT_Done_Glyph(gl);
|
|
|
|
}
|
2002-08-27 09:59:22 +00:00
|
|
|
}
|
|
|
|
}
|
2005-01-11 15:02:29 +00:00
|
|
|
#endif
|
2002-08-27 09:59:22 +00:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
2003-02-08 20:12:25 +00:00
|
|
|
@interface FTFontInfo (experimental_glyph_printing_extension)
|
2006-07-04 21:54:48 +00:00
|
|
|
- (const char *) nameOfGlyph: (NSGlyph)g;
|
2003-02-08 20:12:25 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation FTFontInfo (experimental_glyph_printing_extension)
|
2006-07-04 21:54:48 +00:00
|
|
|
- (const char *) nameOfGlyph: (NSGlyph)g
|
2003-02-08 20:12:25 +00:00
|
|
|
{
|
|
|
|
static char buf[1024]; /* !!TODO!! */
|
2005-01-11 15:02:29 +00:00
|
|
|
FT_Size size;
|
2003-02-08 20:12:25 +00:00
|
|
|
FT_Face face;
|
|
|
|
|
2003-03-03 19:06:55 +00:00
|
|
|
g--;
|
2005-01-11 15:02:29 +00:00
|
|
|
if (FTC_Manager_LookupSize(ftc_manager, &scaler, &size))
|
2003-02-08 20:12:25 +00:00
|
|
|
return ".notdef";
|
2005-01-11 15:02:29 +00:00
|
|
|
face = size->face;
|
2003-02-08 20:12:25 +00:00
|
|
|
|
|
|
|
if (FT_Get_Glyph_Name(face, g, buf, sizeof(buf)))
|
|
|
|
return ".notdef";
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|