/**
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:
The default sizes are:
Font sizes list with (none) default to NSFontSize.
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 = 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]; } } /**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; } /**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; }