/** NSFont The font class Copyright (C) 1996 Free Software Foundation, Inc. Author: Ovidiu Predescu 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 or write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #import #import #import #import #import #import #import #import #import #import #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; } /** NSFont

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.

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:

NSBoldFont Helvetica-Bold (System bold font) NSControlContentFont System font NSFont Helvetica (System Font) NSLabelFont System font NSMenuFont System font NSMenuBarFont System font NSMessageFont System font NSPaletteFont System bold font NSTitleBarFont System bold font NSToolTipsFont System font NSUserFixedPitchFont Courier NSUserFont System font

The default sizes are:

NSBoldFontSize (none) NSControlContentFontSize (none) NSFontSize 12 (System Font Size) NSLabelFontSize (none) NSMenuFontSize (none) NSMiniFontSize 6 NSMessageFontSize (none) NSPaletteFontSize (none) NSSmallFontSize 9 NSTitleBarFontSize (none) NSToolTipsFontSize (none) NSUserFixedPitchFontSize (none) NSUserFontSize (none)

Font sizes list with (none) default to NSFontSize.

*/ @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. */ /**

Returns the default bold font for use in menus and heading in standard gui components. If fontSize is <= 0, the default size is used.

See Also: +fontWithName:size:

*/ + (NSFont*) boldSystemFontOfSize: (CGFloat)fontSize { return getNSFont(fontSize, RoleBoldSystemFont); } /**

Returns the default font for use in menus and heading in standard gui components. If fontSize is <= 0, the default size is used.

See Also: +boldSystemFontOfSize: userFontOfSize: userFixedPitchFontOfSize: +fontWithName:size:

*/ + (NSFont*) systemFontOfSize: (CGFloat)fontSize { return getNSFont(fontSize, RoleSystemFont); } /**

Returns the default fixed pitch font for use in locations other than standard gui components. If fontSize is <= 0, the default size is used.

See Also: +setUserFixedPitchFont: +userFontOfSize: +boldSystemFontOfSize: +systemFontOfSize: +fontWithName:size:

*/ + (NSFont*) userFixedPitchFontOfSize: (CGFloat)fontSize { return getNSFont(fontSize, RoleUserFixedPitchFont); } /**

Returns the default font for use in locations other than standard gui components. If fontSize is <= 0, the default size is used.

See Also: +setUserFont: +boldSystemFontOfSize: systemFontOfSize: userFixedPitchFontOfSize: +fontWithName:size:

*/ + (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]; } } /**

Returns an array of the names of preferred fonts.

See Also: +setPreferredFontNames:

*/ + (NSArray*) preferredFontNames { return _preferredFonts; } /* Setting the preferred user fonts*/ + (void) setUserFixedPitchFont: (NSFont*)aFont { setNSFont (@"NSUserFixedPitchFont", aFont); } + (void) setUserFont: (NSFont*)aFont { setNSFont (@"NSUserFont", aFont); } /**

Sets an array of the names of preferred fonts to fontsNames/

See Also: +preferredFontNames

*/ + (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 = 9; } 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 = 6; } return fontSize; } case NSSmallControlSize: return [self smallSystemFontSize]; case NSRegularControlSize: default: return [self systemFontSize]; } } /**

Returns an autoreleased font with name aFontName and matrix 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]. 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.

*/ + (NSFont*) fontWithName: (NSString*)aFontName matrix: (const CGFloat*)fontMatrix { NSFont *font; font = [placeHolder initWithName: aFontName matrix: fontMatrix screenFont: NO role: RoleExplicit]; return AUTORELEASE(font); } /**

Returns an autoreleased font with name aFontName and size fontSize.

*

Fonts created using this method will automatically flip themselves * when set in a flipped view.

*/ + (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; } /** * 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].
* 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]; } /**

This method returns nil in the GNUstep implementation

*/ - (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; }