libs-gui/Source/NSFont.m
Sergii Stoian 5884e55419 * Source/NSFont.m (smallSystemFontSize): return 10 as default value.
Update documention comment regarding default values for NSMiniFontSize
ans NSSmallFontSize.
2019-12-12 23:20:12 +02:00

1574 lines
42 KiB
Objective-C

/** <title>NSFont</title>
<abstract>The font class</abstract>
Copyright (C) 1996 Free Software Foundation, Inc.
Author: Ovidiu Predescu <ovidiu@net-community.com>
Date: February 1997
A completely rewritten version of the original source by Scott Christley.
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
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.
*/
#include "config.h"
#import <Foundation/NSAffineTransform.h>
#import <Foundation/NSCoder.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSUserDefaults.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSMapTable.h>
#import <Foundation/NSException.h>
#import <Foundation/NSDebug.h>
#import <Foundation/NSValue.h>
#import "AppKit/NSGraphicsContext.h"
#import "AppKit/NSFont.h"
#import "AppKit/NSFontDescriptor.h"
#import "AppKit/NSFontManager.h"
#import "AppKit/NSView.h"
#import "GNUstepGUI/GSFontInfo.h"
@interface NSFont (Private)
- (id) initWithName: (NSString*)name
matrix: (const CGFloat*)fontMatrix
screenFont: (BOOL)screenFont
role: (int)role;
+ (NSFont*) _fontWithName: (NSString*)aFontName
size: (CGFloat)fontSize
role: (int)role;
@end
static int currentVersion = 3;
/*
Instances of GSFontMapKey are used to find cached font instances in
globalFontMap.
*/
@interface GSFontMapKey : NSObject
{
@public
NSString *name;
BOOL screenFont;
int role;
int matrix[6];
unsigned int hash;
}
@end
@implementation GSFontMapKey
-(NSUInteger) hash
{
return hash;
}
-(BOOL) isEqual: (id)other
{
GSFontMapKey *o;
if (![other isKindOfClass: object_getClass(self)])
return NO;
o = other;
if (hash != o->hash || screenFont != o->screenFont || role != o->role)
return NO;
if (![name isEqualToString: o->name])
return NO;
if (matrix[0] != o->matrix[0]
|| matrix[1] != o->matrix[1]
|| matrix[2] != o->matrix[2]
|| matrix[3] != o->matrix[3]
|| matrix[4] != o->matrix[4]
|| matrix[5] != o->matrix[5])
return NO;
return YES;
}
-(void) dealloc
{
DESTROY(name);
[super dealloc];
}
@end
static GSFontMapKey *
keyForFont(NSString *name, const CGFloat *matrix,
BOOL screenFont, int role)
{
GSFontMapKey *d;
d=[GSFontMapKey alloc];
d->name = [name copy];
d->screenFont = screenFont;
d->role = role;
d->matrix[0] = matrix[0] * 1000;
d->matrix[1] = matrix[1] * 1000;
d->matrix[2] = matrix[2] * 1000;
d->matrix[3] = matrix[3] * 1000;
d->matrix[4] = matrix[4] * 1000;
d->matrix[5] = matrix[5] * 1000;
d->hash = [d->name hash] + screenFont + role * 4
+ d->matrix[0] + d->matrix[1] + d->matrix[2] + d->matrix[3];
return d;
}
/**
<unit>
<heading>NSFont</heading>
<p>The NSFont class allows control of the fonts used for displaying
text anywhere on the screen. The primary methods for getting a
particular font are +fontWithName:matrix: and +fontWithName:size: which
take the name and size of a particular font and return the NSFont object
associated with that font. In addition there are several convenience
mathods which make it easier to get certain types of fonts. </p>
<p>In particular, there are several methods to get the standard fonts
used by the Application to display text for a partiuclar purpose. See
the class methods listed below for more information. These default
fonts can be set using the user defaults system. The default
font names available are:
</p>
<list>
<item>NSBoldFont Helvetica-Bold (System bold font)</item>
<item>NSControlContentFont System font</item>
<item>NSFont Helvetica (System Font)</item>
<item>NSLabelFont System font</item>
<item>NSMenuFont System font</item>
<item>NSMenuBarFont System font</item>
<item>NSMessageFont System font</item>
<item>NSPaletteFont System bold font</item>
<item>NSTitleBarFont System bold font</item>
<item>NSToolTipsFont System font</item>
<item>NSUserFixedPitchFont Courier</item>
<item>NSUserFont System font</item>
</list>
<p>
The default sizes are:
</p>
<list>
<item>NSBoldFontSize (none)</item>
<item>NSControlContentFontSize (none)</item>
<item>NSFontSize 12 (System Font Size)</item>
<item>NSLabelFontSize (none)</item>
<item>NSMenuFontSize (none)</item>
<item>NSMiniFontSize 8</item>
<item>NSMessageFontSize (none)</item>
<item>NSPaletteFontSize (none)</item>
<item>NSSmallFontSize 10</item>
<item>NSTitleBarFontSize (none)</item>
<item>NSToolTipsFontSize (none)</item>
<item>NSUserFixedPitchFontSize (none)</item>
<item>NSUserFontSize (none)</item>
</list>
<p>
Font sizes list with (none) default to NSFontSize.
</p>
</unit> */
@implementation NSFont
/* Class variables*/
/* See comments in +initialize. */
static NSFont *placeHolder = nil;
/* Fonts that are preferred by the application */
static NSArray *_preferredFonts;
/* Class for fonts */
static Class NSFontClass = 0;
/* Cache all created fonts for reuse. */
static NSMapTable* globalFontMap = 0;
static NSUserDefaults *defaults = nil;
/*
The valid font roles. Note that these values are used when encoding and
decoding, so entries may never be removed. Entries may be added after the
last entry, and entries don't have to actually be handled.
Note that these values are multiplied by two before they are used since the
lowest bit is used to indicate an explicit size. If the lowest bit is set,
the size is explicitly specified and encoded.
*/
enum FontRoles
{
RoleExplicit=0,
RoleBoldSystemFont,
RoleSystemFont,
RoleUserFixedPitchFont,
RoleUserFont,
RoleTitleBarFont,
RoleMenuFont,
RoleMessageFont,
RolePaletteFont,
RoleToolTipsFont,
RoleControlContentFont,
RoleLabelFont,
RoleMenuBarFont,
RoleMax
};
typedef struct
{
/* Defaults key for this font. */
NSString *key;
/* If there's no defaults key, fall back to the font for this role. */
int fallback;
/* If there's no other role to fall back to, use this font. */
NSString *defaultFont;
/* Cached font for the default size of this role. */
NSFont *cachedFont;
} font_role_info_t;
/*
This table, through getNSFont, controls the behavior of getting the standard
fonts, and must match the table in the documentation above. Each entry should
have a fallback or a defaultFont. There must be a default font for the system
font. Bad Things will happen if entries are invalid.
*/
static font_role_info_t font_roles[RoleMax]={
{nil , 0 , nil, nil},
{@"NSBoldFont" , 0 , nil /* set by init_font_roles */, nil},
{@"NSFont" , 0 , nil /* set by init_font_roles */, nil},
{@"NSUserFixedPitchFont", 0 , nil /* set by init_font_roles */, nil},
{@"NSUserFont" , RoleSystemFont , nil, nil},
{@"NSTitleBarFont" , RoleBoldSystemFont, nil, nil},
{@"NSMenuFont" , RoleSystemFont , nil, nil},
{@"NSMessageFont" , RoleSystemFont , nil, nil},
{@"NSPaletteFont" , RoleBoldSystemFont, nil, nil},
{@"NSToolTipsFont" , RoleSystemFont , nil, nil},
{@"NSControlContentFont", RoleSystemFont , nil, nil},
{@"NSLabelFont" , RoleSystemFont , nil, nil},
{@"NSMenuBarFont" , RoleSystemFont , nil, nil}
};
static BOOL did_init_font_roles;
/*
Called by getNSFont, since font_roles is only accessed from that function
(or fontNameForRole, which is only called by getNSFont). This assures that the
function is called before the table is used, and that it's called _after_ the
backend has been loaded (or, if it isn't, the _fontWithName:... calls will
fail anyway).
*/
static void init_font_roles(void)
{
GSFontEnumerator *e = [GSFontEnumerator sharedEnumerator];
font_roles[RoleSystemFont].defaultFont = [e defaultSystemFontName];
font_roles[RoleBoldSystemFont].defaultFont = [e defaultBoldSystemFontName];
font_roles[RoleUserFixedPitchFont].defaultFont = [e defaultFixedPitchFontName];
}
static NSString *fontNameForRole(int role, int *actual_entry)
{
int i;
NSString *fontName;
i = role;
while (1)
{
fontName = [defaults stringForKey: font_roles[i].key];
if (fontName)
{
break;
}
else if (font_roles[i].fallback)
{
i = font_roles[i].fallback;
}
else if (font_roles[i].defaultFont)
{
fontName = font_roles[i].defaultFont;
break;
}
else
{
NSCAssert(NO, @"Invalid font role table entry.");
}
}
if (actual_entry)
*actual_entry = i;
return fontName;
}
static NSFont *getNSFont(CGFloat fontSize, int role)
{
NSString *fontName;
NSFont *font;
BOOL defaultSize;
int i;
int font_role;
NSCAssert(role > RoleExplicit && role < RoleMax, @"Invalid font role.");
if (!did_init_font_roles)
{
init_font_roles();
did_init_font_roles = YES;
}
font_role = role * 2;
defaultSize = (fontSize <= 0.0);
if (defaultSize)
{
if (font_roles[role].cachedFont)
return AUTORELEASE(RETAIN(font_roles[role].cachedFont));
fontSize = [defaults floatForKey:
[NSString stringWithFormat: @"%@Size", font_roles[role].key]];
if (!fontSize)
fontSize = [NSFont systemFontSize];
}
else
{
font_role |= 1;
}
fontName = fontNameForRole(role, &i);
font = [NSFontClass _fontWithName: fontName
size: fontSize
role: font_role];
/* That font couldn't be found. */
if (font == nil)
{
/* Warn using the role that specified the invalid font. */
NSLog(@"The font specified for %@, %@, can't be found.",
font_roles[i].key, fontName);
/* Try the system font. */
fontName = fontNameForRole(RoleSystemFont, NULL);
font = [NSFontClass _fontWithName: fontName
size: fontSize
role: font_role];
if (font == nil)
{
/* Try the default system font and size. */
fontName = font_roles[RoleSystemFont].defaultFont;
font = [NSFontClass _fontWithName: fontName
size: 12.0
role: font_role];
/* It seems we can't get any font here! Try some well known
* fonts as a last resort. */
if (font == nil)
{
font = [NSFontClass _fontWithName: @"Helvetica"
size: 12.0
role: font_role];
}
if (font == nil)
{
font = [NSFontClass _fontWithName: @"Courier"
size: 12.0
role: font_role];
}
if (font == nil)
{
font = [NSFontClass _fontWithName: @"Fixed"
size: 12.0
role: font_role];
}
}
}
if (defaultSize)
ASSIGN(font_roles[role].cachedFont, font);
return font;
}
static void setNSFont(NSString *key, NSFont *font)
{
int i;
[defaults setObject: [font fontName] forKey: key];
[defaults setObject: [NSNumber numberWithFloat: [font pointSize]]
forKey: [NSString stringWithFormat: @"%@Size",key]];
for (i = 1; i < RoleMax; i++)
{
DESTROY(font_roles[i].cachedFont);
}
/* Don't care about errors */
[defaults synchronize];
}
//
// Class methods
//
+ (void) initialize
{
if (self == [NSFont class])
{
NSFontClass = self;
/*
* The placeHolder is a dummy NSFont instance which is never used
* as a font ... the initialiser knows that whenever it gets the
* placeHolder it should either return a cached font or return a
* newly allocated font to replace it. This mechanism stops the
* +fontWithName:... methods from having to allocate fonts instances
* which would immediately have to be released for replacement by
* a cache object.
*/
placeHolder = [self alloc];
globalFontMap = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSNonRetainedObjectMapValueCallBacks, 64);
if (defaults == nil)
{
defaults = RETAIN([NSUserDefaults standardUserDefaults]);
}
_preferredFonts = [defaults objectForKey: @"NSPreferredFonts"];
[self setVersion: currentVersion];
}
}
/* Getting the preferred user fonts. */
/**<p>Returns the default bold font for use in menus and heading in standard
gui components. If fontSize is &lt;= 0, the default
size is used.</p><p>See Also: +fontWithName:size:</p>
*/
+ (NSFont*) boldSystemFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RoleBoldSystemFont);
}
/**<p> Returns the default font for use in menus and heading in standard
gui components. If fontSize is &lt;= 0, the default
size is used.</p><p>See Also: +boldSystemFontOfSize: userFontOfSize:
userFixedPitchFontOfSize: +fontWithName:size:</p>
*/
+ (NSFont*) systemFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RoleSystemFont);
}
/**<p>Returns the default fixed pitch font for use in locations other
than standard gui components. If fontSize is &lt;= 0, the default
size is used.</p><p>See Also: +setUserFixedPitchFont: +userFontOfSize:
+boldSystemFontOfSize: +systemFontOfSize: +fontWithName:size:</p>
*/
+ (NSFont*) userFixedPitchFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RoleUserFixedPitchFont);
}
/**<p> Returns the default font for use in locations other
than standard gui components. If fontSize is &lt;= 0, the default
size is used.</p><p>See Also: +setUserFont: +boldSystemFontOfSize:
systemFontOfSize: userFixedPitchFontOfSize: +fontWithName:size:</p>
*/
+ (NSFont*) userFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RoleUserFont);
}
+ (NSFont *) fontWithDescriptor: (NSFontDescriptor *)descriptor
size: (CGFloat)size
{
NSArray *a;
descriptor = [descriptor matchingFontDescriptorWithMandatoryKeys:
[NSSet setWithArray: [[descriptor fontAttributes] allKeys]]];
if (descriptor == nil)
return nil;
a = [[NSFontManager sharedFontManager] availableFontNamesMatchingFontDescriptor:
descriptor];
if ((a == nil) || ([a count] == 0))
return nil;
return [self fontWithName: [a objectAtIndex: 0]
size: size];
}
+ (NSFont*) fontWithDescriptor: (NSFontDescriptor*)descriptor
textTransform: (NSAffineTransform*)transform
{
NSArray *a;
CGFloat fontMatrix[6];
NSAffineTransformStruct ats;
descriptor = [descriptor matchingFontDescriptorWithMandatoryKeys:
[NSSet setWithArray: [[descriptor fontAttributes] allKeys]]];
if (descriptor == nil)
return nil;
a = [[NSFontManager sharedFontManager] availableFontNamesMatchingFontDescriptor:
descriptor];
if ((a == nil) || ([a count] == 0))
return nil;
ats = [transform transformStruct];
fontMatrix[0] = ats.m11;
fontMatrix[1] = ats.m12;
fontMatrix[2] = ats.m21;
fontMatrix[3] = ats.m22;
fontMatrix[4] = ats.tX;
fontMatrix[5] = ats.tY;
return [self fontWithName: [a objectAtIndex: 0]
matrix: fontMatrix];
}
+ (NSFont *) fontWithDescriptor: (NSFontDescriptor *)descriptor
size: (CGFloat)size
textTransform: (NSAffineTransform *)transform
{
if (transform)
{
return [self fontWithDescriptor: descriptor
textTransform: transform];
}
else
{
return [self fontWithDescriptor: descriptor
size: size];
}
}
/**<p>Returns an array of the names of preferred fonts.</p>
<p>See Also: +setPreferredFontNames:</p>
*/
+ (NSArray*) preferredFontNames
{
return _preferredFonts;
}
/* Setting the preferred user fonts*/
+ (void) setUserFixedPitchFont: (NSFont*)aFont
{
setNSFont (@"NSUserFixedPitchFont", aFont);
}
+ (void) setUserFont: (NSFont*)aFont
{
setNSFont (@"NSUserFont", aFont);
}
/** <p>Sets an array of the names of preferred fonts to fontsNames/</p>
<p>See Also: +preferredFontNames</p>
*/
+ (void) setPreferredFontNames: (NSArray*)fontNames
{
ASSIGN(_preferredFonts, fontNames);
// FIXME: Should this store back the preferred fonts in the user defaults?
}
/* Getting various fonts*/
+ (NSFont*) controlContentFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RoleControlContentFont);
}
+ (NSFont*) labelFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RoleLabelFont);
}
+ (NSFont*) menuFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RoleMenuFont);
}
+ (NSFont*) menuBarFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RoleMenuBarFont);
}
+ (NSFont*) titleBarFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RoleTitleBarFont);
}
+ (NSFont*) messageFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RoleMessageFont);
}
+ (NSFont*) paletteFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RolePaletteFont);
}
+ (NSFont*) toolTipsFontOfSize: (CGFloat)fontSize
{
return getNSFont(fontSize, RoleToolTipsFont);
}
//
// Font Sizes
//
+ (CGFloat) labelFontSize
{
CGFloat fontSize = [defaults floatForKey: @"NSLabelFontSize"];
if (fontSize == 0)
{
return [self systemFontSize];
}
return fontSize;
}
+ (CGFloat) smallSystemFontSize
{
CGFloat fontSize = [defaults floatForKey: @"NSSmallFontSize"];
if (fontSize == 0)
{
fontSize = 10;
}
return fontSize;
}
+ (CGFloat) systemFontSize
{
CGFloat fontSize = [defaults floatForKey: @"NSFontSize"];
if (fontSize == 0)
{
fontSize = 12;
}
return fontSize;
}
+ (CGFloat) systemFontSizeForControlSize: (NSControlSize)controlSize
{
switch (controlSize)
{
case NSMiniControlSize:
{
CGFloat fontSize = [defaults floatForKey: @"NSMiniFontSize"];
if (fontSize == 0)
{
fontSize = 8;
}
return fontSize;
}
case NSSmallControlSize:
return [self smallSystemFontSize];
case NSRegularControlSize:
default:
return [self systemFontSize];
}
}
/** <p>Returns an autoreleased font with name aFontName and matrix fontMatrix
.</p><p>The fontMatrix is a standard size element matrix as used in
PostScript to describe the scaling of the font, typically it just includes
the font size as [fontSize 0 0 fontSize 0 0]. You can use the constant
NSFontIdentityMatrix in place of [1 0 0 1 0 0]. If NSFontIdentityMatrix,
then the font will automatically flip itself when set in a flipped view.
</p>
*/
+ (NSFont*) fontWithName: (NSString*)aFontName
matrix: (const CGFloat*)fontMatrix
{
NSFont *font;
font = [placeHolder initWithName: aFontName
matrix: fontMatrix
screenFont: NO
role: RoleExplicit];
return AUTORELEASE(font);
}
/**<p> Returns an autoreleased font with name aFontName and size fontSize.</p>
* <p>Fonts created using this method will automatically flip themselves
* when set in a flipped view.</p>
*/
+ (NSFont*) fontWithName: (NSString*)aFontName
size: (CGFloat)fontSize
{
return [self _fontWithName: aFontName
size: fontSize
role: RoleExplicit];
}
+ (NSFont*) _fontWithName: (NSString*)aFontName
size: (CGFloat)fontSize
role: (int)aRole
{
NSFont *font;
CGFloat fontMatrix[6] = { 0, 0, 0, 0, 0, 0 };
if (fontSize == 0)
{
fontSize = [defaults floatForKey: @"NSUserFontSize"];
if (fontSize == 0)
{
fontSize = 12;
}
}
fontMatrix[0] = fontSize;
fontMatrix[3] = fontSize;
font = [placeHolder initWithName: aFontName
matrix: fontMatrix
screenFont: NO
role: aRole];
return AUTORELEASE(font);
}
/**
*/
+ (void) useFont: (NSString*)aFontName
{
[GSCurrentContext() useFont: aFontName];
}
//
// Instance methods
//
- (id) init
{
[NSException raise: NSInternalInconsistencyException
format: @"Called -init on NSFont ... illegal"];
return self;
}
/*
Last fallback: If a system font was explicitly requested
and this font does not exist, try to replace it with the
corresponding font in the current setup.
*/
- (NSString*) _replacementFontName
{
if (([fontName isEqualToString: @"Helvetica"] &&
![font_roles[RoleSystemFont].defaultFont isEqualToString: @"Helvetica"])
|| ([fontName isEqualToString: @"LucidaGrande"]))
{
return font_roles[RoleSystemFont].defaultFont;
}
else if (([fontName isEqualToString: @"Helvetica-Bold"] &&
![font_roles[RoleBoldSystemFont].defaultFont isEqualToString: @"Helvetica-Bold"])
|| ([fontName isEqualToString: @"LucidaGrande-Bold"]))
{
return font_roles[RoleBoldSystemFont].defaultFont;
}
else if ([fontName isEqualToString: @"Courier"] &&
![font_roles[RoleUserFixedPitchFont].defaultFont isEqualToString: @"Courier"])
{
return font_roles[RoleUserFixedPitchFont].defaultFont;
}
else if ([fontName hasPrefix: @"Helvetica-"] &&
![font_roles[RoleSystemFont].defaultFont isEqualToString: @"Helvetica"])
{
return [NSString stringWithFormat: @"%@-%@",
font_roles[RoleSystemFont].defaultFont,
[fontName substringFromIndex: 10]];
}
return nil;
}
/** <init />
* Initializes a newly created font instance from the name and
* information given in the fontMatrix. The fontMatrix is a standard
* size element matrix as used in PostScript to describe the scaling
* of the font, typically it just includes the font size as
* [fontSize 0 0 fontSize 0 0].<br />
* This method may destroy the receiver and return a cached instance.
*/
- (id) initWithName: (NSString*)name
matrix: (const CGFloat*)fontMatrix
screenFont: (BOOL)screen
role: (int)aRole
{
GSFontMapKey *key;
NSFont *font;
/* Should never be called on an initialised font! */
NSAssert(fontName == nil, NSInternalInconsistencyException);
/* Check whether the font is cached */
key = keyForFont(name, fontMatrix,
screen, aRole);
font = (id)NSMapGet(globalFontMap, (void *)key);
if (font == nil)
{
if (self == placeHolder)
{
/*
* If we are initialising the placeHolder, we actually want to
* leave it be (for later re-use) and initialise a newly created
* instance instead.
*/
self = [NSFontClass alloc];
}
fontName = [name copy];
memcpy(matrix, fontMatrix, sizeof(matrix));
screenFont = screen;
role = aRole;
fontInfo = RETAIN([GSFontInfo fontInfoForFontName: fontName
matrix: fontMatrix
screenFont: screen]);
if ((fontInfo == nil) && (aRole == RoleExplicit))
{
NSString *replacementFontName = [self _replacementFontName];
if (replacementFontName != nil)
{
fontInfo = RETAIN([GSFontInfo fontInfoForFontName: replacementFontName
matrix: fontMatrix
screenFont: screen]);
}
}
if (fontInfo == nil)
{
DESTROY(fontName);
DESTROY(key);
RELEASE(self);
return nil;
}
/* Cache the font for later use */
NSMapInsert(globalFontMap, (void *)key, (void *)self);
}
else
{
if (self != placeHolder)
{
RELEASE(self);
}
self = RETAIN(font);
}
RELEASE(key);
return self;
}
- (void) dealloc
{
if (fontName != nil)
{
GSFontMapKey *key;
key = keyForFont(fontName, matrix,
screenFont, role);
NSMapRemove(globalFontMap, (void *)key);
RELEASE(key);
RELEASE(fontName);
}
TEST_RELEASE(fontInfo);
DESTROY(cachedFlippedFont);
DESTROY(cachedScreenFont);
[super dealloc];
}
- (NSString *) description
{
NSString *nameWithMatrix;
NSString *description;
nameWithMatrix = [[NSString alloc] initWithFormat:
@"%@ %.3f %.3f %.3f %.3f %.3f %.3f %c %i", fontName,
matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5],
screenFont ? 'S' : 'P',
role];
description = [[super description] stringByAppendingFormat: @" %@",
nameWithMatrix];
RELEASE(nameWithMatrix);
return description;
}
- (BOOL) isEqual: (id)anObject
{
if (anObject == self)
return YES;
if ([anObject isKindOfClass: object_getClass(self)] == NO)
return NO;
if ([[anObject fontName] isEqual: fontName] == NO)
return NO;
if (memcmp(matrix, [(NSFont*)anObject matrix], sizeof(matrix)) != 0)
return NO;
return YES;
}
- (NSUInteger) hash
{
int i, sum;
sum = 0;
for (i = 0; i < 6; i++)
sum += matrix[i] * ((i+1) * 17);
return ([fontName hash] + sum);
}
/**
* The NSFont class caches instances ... to actually make copies
* of instances would defeat the whole point of caching, so the
* effect of copying an NSFont is imply to retain it.
*/
- (id) copyWithZone: (NSZone*)zone
{
return RETAIN(self);
}
- (NSFont *)_flippedViewFont
{
if (cachedFlippedFont == nil)
{
CGFloat fontMatrix[6];
memcpy(fontMatrix, matrix, sizeof(matrix));
fontMatrix[3] *= -1;
cachedFlippedFont = [placeHolder initWithName: fontName
matrix: fontMatrix
screenFont: screenFont
role: role];
}
return AUTORELEASE(RETAIN(cachedFlippedFont));
}
static BOOL flip_hack;
+(void) _setFontFlipHack: (BOOL)flip
{
flip_hack = flip;
}
//
// Setting the Font
//
/** Sets the receiver as the font used for text drawing operations. If the
current view is a flipped view, the reciever automatically flips itself
to display correctly in the flipped view */
- (void) set
{
[self setInContext: GSCurrentContext()];
}
- (void) setInContext: (NSGraphicsContext*)context
{
if ([[NSView focusView] isFlipped] || flip_hack)
[context GSSetFont: [[self _flippedViewFont] fontRef]];
else
[context GSSetFont: [self fontRef]];
[context useFont: fontName];
}
//
// Querying the Font
//
- (CGFloat) pointSize
{
return [fontInfo pointSize];
}
- (NSString*) fontName
{
return fontName;
}
- (const CGFloat*) matrix
{
return matrix;
}
- (NSAffineTransform*) textTransform
{
NSAffineTransform *transform;
NSAffineTransformStruct tstruct;
tstruct.m11 = matrix[0];
tstruct.m12 = matrix[1];
tstruct.m21 = matrix[2];
tstruct.m22 = matrix[3];
tstruct.tX = matrix[4];
tstruct.tY = matrix[5];
transform = [NSAffineTransform transform];
[transform setTransformStruct: tstruct];
return transform;
}
- (NSString*) encodingScheme
{
return [fontInfo encodingScheme];
}
- (NSString*) familyName
{
return [fontInfo familyName];
}
- (NSRect) boundingRectForFont
{
return [fontInfo boundingRectForFont];
}
- (BOOL) isFixedPitch
{
return [fontInfo isFixedPitch];
}
- (BOOL) isBaseFont
{
return [fontInfo isBaseFont];
}
/* Usually the display name of font is the font name.*/
- (NSString*) displayName
{
return fontName;
}
- (NSDictionary*) afmDictionary
{
return [fontInfo afmDictionary];
}
/**<p>This method returns nil in the GNUstep implementation</p>
*/
- (NSString*) afmFileContents
{
return [fontInfo afmFileContents];
}
- (NSFont*) printerFont
{
if (!screenFont)
return self;
return AUTORELEASE([placeHolder initWithName: fontName
matrix: matrix
screenFont: NO
role: role]);
}
- (NSFont*) screenFont
{
if (screenFont)
return self;
/*
If we haven't already created the real screen font instance, do so now.
Note that if the font has no corresponding screen font, cachedScreenFont
will be set to nil.
*/
if (cachedScreenFont == nil)
cachedScreenFont = [placeHolder initWithName: fontName
matrix: matrix
screenFont: YES
role: role];
return AUTORELEASE(RETAIN(cachedScreenFont));
}
- (NSFont*) screenFontWithRenderingMode: (NSFontRenderingMode)mode
{
// FIXME
return [self screenFont];
}
- (NSFontRenderingMode) renderingMode
{
// FIXME
return NSFontDefaultRenderingMode;
}
- (CGFloat) ascender { return [fontInfo ascender]; }
- (CGFloat) descender { return [fontInfo descender]; }
- (CGFloat) capHeight { return [fontInfo capHeight]; }
- (CGFloat) italicAngle { return [fontInfo italicAngle]; }
- (NSSize) maximumAdvancement { return [fontInfo maximumAdvancement]; }
- (NSSize) minimumAdvancement { return [fontInfo minimumAdvancement]; }
- (CGFloat) underlinePosition { return [fontInfo underlinePosition]; }
- (CGFloat) underlineThickness { return [fontInfo underlineThickness]; }
- (CGFloat) xHeight { return [fontInfo xHeight]; }
- (CGFloat) defaultLineHeightForFont { return [fontInfo defaultLineHeightForFont]; }
- (CGFloat) leading
{
// FIXME
return 0.0;
}
/* Computing font metrics attributes*/
- (CGFloat) widthOfString: (NSString*)string
{
return [fontInfo widthOfString: string];
}
- (NSUInteger) numberOfGlyphs
{
return [fontInfo numberOfGlyphs];
}
- (NSCharacterSet*) coveredCharacterSet
{
return [fontInfo coveredCharacterSet];
}
- (NSFontDescriptor*) fontDescriptor
{
return [fontInfo fontDescriptor];
}
/* The following methods have to be implemented by backends */
//
// Manipulating Glyphs
//
- (NSSize) advancementForGlyph: (NSGlyph)aGlyph
{
return [fontInfo advancementForGlyph: aGlyph];
}
- (NSRect) boundingRectForGlyph: (NSGlyph)aGlyph
{
return [fontInfo boundingRectForGlyph: aGlyph];
}
- (BOOL) glyphIsEncoded: (NSGlyph)aGlyph
{
return [fontInfo glyphIsEncoded: aGlyph];
}
- (NSMultibyteGlyphPacking) glyphPacking
{
return [fontInfo glyphPacking];
}
- (NSGlyph) glyphWithName: (NSString*)glyphName
{
return [fontInfo glyphWithName: glyphName];
}
- (NSPoint) positionOfGlyph: (NSGlyph)curGlyph
precededByGlyph: (NSGlyph)prevGlyph
isNominal: (BOOL*)nominal
{
return [fontInfo positionOfGlyph: curGlyph precededByGlyph: prevGlyph
isNominal: nominal];
}
- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
forCharacter: (unichar)aChar
struckOverRect: (NSRect)aRect
{
return [fontInfo positionOfGlyph: aGlyph
forCharacter: aChar
struckOverRect: aRect];
}
- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
struckOverGlyph: (NSGlyph)baseGlyph
metricsExist: (BOOL *)flag
{
return [fontInfo positionOfGlyph: aGlyph
struckOverGlyph: baseGlyph
metricsExist: flag];
}
- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
struckOverRect: (NSRect)aRect
metricsExist: (BOOL *)flag
{
return [fontInfo positionOfGlyph: aGlyph
struckOverRect: aRect
metricsExist: flag];
}
- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
withRelation: (NSGlyphRelation)relation
toBaseGlyph: (NSGlyph)baseGlyph
totalAdvancement: (NSSize *)offset
metricsExist: (BOOL *)flag
{
return [fontInfo positionOfGlyph: aGlyph
withRelation: relation
toBaseGlyph: baseGlyph
totalAdvancement: offset
metricsExist: flag];
}
- (int) positionsForCompositeSequence: (NSGlyph *)glyphs
numberOfGlyphs: (int)numGlyphs
pointArray: (NSPoint *)points
{
int i;
NSGlyph base = glyphs[0];
points[0] = NSZeroPoint;
for (i = 1; i < numGlyphs; i++)
{
BOOL flag;
// This only places the glyphs relative to the base glyph
// not to each other
points[i] = [self positionOfGlyph: glyphs[i]
struckOverGlyph: base
metricsExist: &flag];
if (!flag)
return i - 1;
}
return i;
}
- (void) getAdvancements: (NSSizeArray)advancements
forGlyphs: (const NSGlyph*)glyphs
count: (NSUInteger)count
{
// FIXME
int i;
for (i = 0; i < count; i++)
{
advancements[i] = [self advancementForGlyph: glyphs[i]];
}
}
- (void) getAdvancements: (NSSizeArray)advancements
forPackedGlyphs: (const void*)glyphs
count: (NSUInteger)count
{
// FIXME
}
- (void) getBoundingRects: (NSRectArray)bounds
forGlyphs: (const NSGlyph*)glyphs
count: (NSUInteger)count
{
// FIXME
int i;
for (i = 0; i < count; i++)
{
bounds[i] = [self boundingRectForGlyph: glyphs[i]];
}
}
- (NSStringEncoding) mostCompatibleStringEncoding
{
return [fontInfo mostCompatibleStringEncoding];
}
//
// NSCoding protocol
//
- (Class) classForCoder
{
return NSFontClass;
}
- (void) encodeWithCoder: (NSCoder*)aCoder
{
if ([aCoder allowsKeyedCoding])
{
[aCoder encodeObject: fontName forKey: @"NSName"];
[aCoder encodeFloat: [self pointSize] forKey: @"NSSize"];
switch (role >> 1)
{
// FIXME: Many cases still missing
case RoleControlContentFont:
[aCoder encodeInt: 16 forKey: @"NSfFlags"];
break;
case RoleLabelFont:
[aCoder encodeInt: 20 forKey: @"NSfFlags"];
break;
case RoleTitleBarFont:
[aCoder encodeInt: 22 forKey: @"NSfFlags"];
break;
default:
break;
}
}
else
{
[aCoder encodeValueOfObjCType: @encode(int) at: &role];
if (role == 0)
{
float fontMatrix[6];
BOOL fix = NO;
fontMatrix[0] = matrix[0];
fontMatrix[1] = matrix[1];
fontMatrix[2] = matrix[2];
fontMatrix[3] = matrix[3];
fontMatrix[4] = matrix[4];
fontMatrix[5] = matrix[5];
[aCoder encodeObject: fontName];
[aCoder encodeArrayOfObjCType: @encode(float) count: 6 at: fontMatrix];
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &fix];
}
else if (role & 1)
{
float size = matrix[0];
[aCoder encodeValueOfObjCType: @encode(float) at: &size];
}
}
}
- (id) initWithCoder: (NSCoder*)aDecoder
{
if ([aDecoder allowsKeyedCoding])
{
NSString *name = [aDecoder decodeObjectForKey: @"NSName"];
float size = [aDecoder decodeFloatForKey: @"NSSize"];
DESTROY(self);
if ([aDecoder containsValueForKey: @"IBIsSystemFont"])
{
self = RETAIN([NSFont systemFontOfSize: size]);
}
else
{
self = RETAIN([NSFont fontWithName: name size: size]);
}
if (self == nil)
{
if ([aDecoder containsValueForKey: @"NSfFlags"])
{
int flags = [aDecoder decodeIntForKey: @"NSfFlags"];
// FIXME
if (flags == 16)
{
return RETAIN([NSFont controlContentFontOfSize: size]);
}
else if (flags == 20)
{
return RETAIN([NSFont labelFontOfSize: size]);
}
else if (flags == 22)
{
return RETAIN([NSFont titleBarFontOfSize: size]);
}
}
self = RETAIN([NSFont systemFontOfSize: size]);
}
return self;
}
else
{
int version = [aDecoder versionForClassName: @"NSFont"];
id name;
float fontMatrix[6];
CGFloat cgMatrix[6];
int the_role;
if (version == 3)
{
[aDecoder decodeValueOfObjCType: @encode(int)
at: &the_role];
}
else
{
the_role = RoleExplicit;
}
if (the_role == RoleExplicit)
{
/* The easy case: an explicit font, or a font encoded with
version <= 2. */
name = [aDecoder decodeObject];
[aDecoder decodeArrayOfObjCType: @encode(float)
count: 6
at: fontMatrix];
if (version >= 2)
{
BOOL fix;
[aDecoder decodeValueOfObjCType: @encode(BOOL)
at: &fix];
}
cgMatrix[0] = fontMatrix[0];
cgMatrix[1] = fontMatrix[1];
cgMatrix[2] = fontMatrix[2];
cgMatrix[3] = fontMatrix[3];
cgMatrix[4] = fontMatrix[4];
cgMatrix[5] = fontMatrix[5];
self = [self initWithName: name
matrix: cgMatrix
screenFont: NO
role: RoleExplicit];
if (self)
return self;
self = [NSFont userFontOfSize: fontMatrix[0]];
NSAssert(self != nil, @"Couldn't find a valid font when decoding.");
return RETAIN(self);
}
else
{
/* A non-explicit font. */
float size;
NSFont *new;
if (the_role & 1)
{
[aDecoder decodeValueOfObjCType: @encode(float)
at: &size];
}
else
{
size = 0.0;
}
switch (the_role >> 1)
{
case RoleBoldSystemFont:
new = [NSFont boldSystemFontOfSize: size];
break;
case RoleSystemFont:
new = [NSFont systemFontOfSize: size];
break;
case RoleUserFixedPitchFont:
new = [NSFont userFixedPitchFontOfSize: size];
break;
case RoleTitleBarFont:
new = [NSFont titleBarFontOfSize: size];
break;
case RoleMenuFont:
new = [NSFont menuFontOfSize: size];
break;
case RoleMessageFont:
new = [NSFont messageFontOfSize: size];
break;
case RolePaletteFont:
new = [NSFont paletteFontOfSize: size];
break;
case RoleToolTipsFont:
new = [NSFont toolTipsFontOfSize: size];
break;
case RoleControlContentFont:
new = [NSFont controlContentFontOfSize: size];
break;
case RoleLabelFont:
new = [NSFont labelFontOfSize: size];
break;
case RoleMenuBarFont:
new = [NSFont menuBarFontOfSize: size];
break;
default:
NSDebugLLog(@"NSFont", @"unknown role %i", the_role);
/* fall through */
case RoleUserFont:
new = [NSFont userFontOfSize: size];
break;
}
RELEASE(self);
if (new)
return RETAIN(new);
new = [NSFont userFontOfSize: size];
NSAssert(new != nil, @"Couldn't find a valid font when decoding.");
return RETAIN(new);
}
}
}
@end /* NSFont */
@implementation NSFont (GNUstep)
//
// Private method for NSFontManager and backend
//
- (GSFontInfo*) fontInfo
{
return fontInfo;
}
- (void *) fontRef
{
if (_fontRef == nil)
_fontRef = fontInfo;
return _fontRef;
}
// This is a private but popular Cocoa method.
- (NSGlyph) _defaultGlyphForChar: (unichar)theChar
{
return [fontInfo glyphForCharacter: theChar];
}
@end
int NSConvertGlyphsToPackedGlyphs(NSGlyph *glBuf,
int count,
NSMultibyteGlyphPacking packing,
char *packedGlyphs)
{
int i;
int j;
j = 0;
// Store the number of glyphs in the first byte.
packedGlyphs[j++] = count;
for (i = 0; i < count; i++)
{
NSGlyph g = glBuf[i];
switch (packing)
{
case NSOneByteGlyphPacking:
packedGlyphs[j++] = (char)(g & 0xFF);
break;
case NSTwoByteGlyphPacking:
packedGlyphs[j++] = (char)((g & 0xFF00) >> 8) ;
packedGlyphs[j++] = (char)(g & 0xFF);
break;
case NSFourByteGlyphPacking:
packedGlyphs[j++] = (char)((g & 0xFF000000) >> 24) ;
packedGlyphs[j++] = (char)((g & 0xFF0000) >> 16);
packedGlyphs[j++] = (char)((g & 0xFF00) >> 8) ;
packedGlyphs[j++] = (char)(g & 0xFF);
break;
case NSJapaneseEUCGlyphPacking:
case NSAsciiWithDoubleByteEUCGlyphPacking:
default:
// FIXME
break;
}
}
return j;
}