macFont.mm
Engine/source/platformMac/macFont.mm
Public Functions
createPlatformFont(const char * name, dsize_t size, U32 charset)
Detailed Description
Public Functions
createPlatformFont(const char * name, dsize_t size, U32 charset)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2013 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#import <Cocoa/Cocoa.h> 25#import "platform/platform.h" 26#import "core/util/tVector.h" 27#import "math/mMathFn.h" 28#import "platformMac/macFont.h" 29#import "core/stringTable.h" 30#import "core/strings/unicode.h" 31#import "console/console.h" 32 33 34//------------------------------------------------------------------------------ 35 36PlatformFont* createPlatformFont( const char* name, dsize_t size, U32 charset ) 37{ 38 PlatformFont* pFont = new OSXFont(); 39 40 if ( pFont->create(name, size, charset) ) 41 return pFont; 42 43 delete pFont; 44 45 return NULL; 46} 47 48//------------------------------------------------------------------------------ 49 50void PlatformFont::enumeratePlatformFonts( Vector<StringTableEntry>& fonts, UTF16 *fontFamily ) 51{ 52 // Fetch available fonts. 53 NSArray* availableFonts = [[NSFontManager sharedFontManager] availableFontNamesWithTraits:0]; 54 55 // Enumerate font names. 56 for (id fontName in availableFonts) 57 { 58 fonts.push_back( StringTable->insert( [fontName UTF8String] ) ); 59 } 60 61 // Release font name. 62 [availableFonts release]; 63} 64 65//------------------------------------------------------------------------------ 66 67OSXFont::OSXFont() 68{ 69 // Reset the rendering color-space. 70 mColorSpace = NULL; 71} 72 73//------------------------------------------------------------------------------ 74 75OSXFont::~OSXFont() 76{ 77 // Destroy the rendering color-space. 78 CGColorSpaceRelease( mColorSpace ); 79} 80 81//------------------------------------------------------------------------------ 82 83bool OSXFont::create( const char* name, dsize_t size, U32 charset ) 84{ 85 // Sanity! 86 AssertFatal( name != NULL, "Cannot create a NULL font name." ); 87 88 // Generate compatible font name. 89 CFStringRef fontName = CFStringCreateWithCString( kCFAllocatorDefault, name, kCFStringEncodingUTF8 ); 90 91 // Sanity! 92 if ( !fontName ) 93 { 94 Con::errorf("Could not handle font name of '%s'.", name ); 95 return false; 96 } 97 98 // Use Windows as a baseline (96 DPI) and adjust accordingly. 99 F32 scaledSize = size * (72.0f/96.0f); 100 scaledSize = mRound(scaledSize); 101 102 // Create the font reference. 103 mFontRef = CTFontCreateWithName( fontName, scaledSize, NULL ); 104 105 // Sanity! 106 if ( !mFontRef ) 107 { 108 Con::errorf( "Could not generate a font reference to font name '%s' of size '%d'", name, size ); 109 return false; 110 } 111 112 // Fetch font metrics. 113 CGFloat ascent = CTFontGetAscent( mFontRef ); 114 CGFloat descent = CTFontGetDescent( mFontRef ); 115 116 // Set baseline. 117 mBaseline = (U32)mRound(ascent); 118 119 // Set height. 120 mHeight = (U32)mRound( ascent + descent ); 121 122 // Create a gray-scale color-space. 123 mColorSpace = CGColorSpaceCreateDeviceGray(); 124 125 // Return status. 126 return true; 127} 128 129//------------------------------------------------------------------------------ 130 131bool OSXFont::isValidChar( const UTF8* str ) const 132{ 133 // since only low order characters are invalid, and since those characters 134 // are single codeunits in UTF8, we can safely cast here. 135 return isValidChar((UTF16)*str); 136} 137 138//------------------------------------------------------------------------------ 139 140bool OSXFont::isValidChar( const UTF16 character) const 141{ 142 // We cut out the ASCII control chars here. Only printable characters are valid. 143 // 0x20 == 32 == space 144 if( character < 0x20 ) 145 return false; 146 147 return true; 148} 149 150//------------------------------------------------------------------------------ 151 152PlatformFont::CharInfo& OSXFont::getCharInfo(const UTF8 *str) const 153{ 154 return getCharInfo( oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)) ); 155} 156 157//------------------------------------------------------------------------------ 158 159PlatformFont::CharInfo& OSXFont::getCharInfo(const UTF16 character) const 160{ 161 // Declare and clear out the CharInfo that will be returned. 162 static PlatformFont::CharInfo characterInfo; 163 dMemset(&characterInfo, 0, sizeof(characterInfo)); 164 165 // prep values for GFont::addBitmap() 166 characterInfo.bitmapIndex = 0; 167 characterInfo.xOffset = 0; 168 characterInfo.yOffset = 0; 169 170 CGGlyph characterGlyph; 171 CGRect characterBounds; 172 CGSize characterAdvances; 173 UniChar unicodeCharacter = character; 174 175 // Fetch font glyphs. 176 if ( !CTFontGetGlyphsForCharacters( mFontRef, &unicodeCharacter, &characterGlyph, (CFIndex)1) ) 177 { 178 // Sanity! 179 //AssertFatal( false, "Cannot create font glyph." ); 180 Con::warnf("Font glyph is messed up. Some characters may render incorrectly."); 181 } 182 183 // Fetch glyph bounding box. 184 CTFontGetBoundingRectsForGlyphs( mFontRef, kCTFontHorizontalOrientation, &characterGlyph, &characterBounds, (CFIndex)1 ); 185 186 // Fetch glyph advances. 187 CTFontGetAdvancesForGlyphs( mFontRef, kCTFontHorizontalOrientation, &characterGlyph, &characterAdvances, (CFIndex)1 ); 188 189 // Set character metrics, 190 characterInfo.xOrigin = (S32)mRound( characterBounds.origin.x ); 191 characterInfo.yOrigin = (S32)mRound( characterBounds.origin.y ); 192 characterInfo.width = (U32)mCeil( characterBounds.size.width ) + 2; 193 characterInfo.height = (U32)mCeil( characterBounds.size.height ) + 2; 194 characterInfo.xIncrement = (S32)mRound( characterAdvances.width ); 195 196 // Finish if character is undrawable. 197 if ( characterInfo.width == 0 && characterInfo.height == 0 ) 198 return characterInfo; 199 200 // Clamp character minimum width. 201 if ( characterInfo.width == 0 ) 202 characterInfo.width = 2; 203 204 if ( characterInfo.height == 0 ) 205 characterInfo.height = 1; 206 207 208 // Allocate a bitmap surface. 209 const U32 bitmapSize = characterInfo.width * characterInfo.height; 210 characterInfo.bitmapData = new U8[bitmapSize]; 211 dMemset(characterInfo.bitmapData, 0x00, bitmapSize); 212 213 // Create a bitmap context. 214 CGContextRef bitmapContext = CGBitmapContextCreate( characterInfo.bitmapData, characterInfo.width, characterInfo.height, 8, characterInfo.width, mColorSpace, kCGImageAlphaNone ); 215 216 // Sanity! 217 AssertFatal( bitmapContext != NULL, "Cannot create font context." ); 218 219 // Render font anti-aliased if font is arbitrarily small. 220 CGContextSetShouldAntialias( bitmapContext, true); 221 CGContextSetShouldSmoothFonts( bitmapContext, true); 222 CGContextSetRenderingIntent( bitmapContext, kCGRenderingIntentAbsoluteColorimetric); 223 CGContextSetInterpolationQuality( bitmapContext, kCGInterpolationNone); 224 CGContextSetGrayFillColor( bitmapContext, 1.0, 1.0); 225 CGContextSetTextDrawingMode( bitmapContext, kCGTextFill); 226 227 // Draw glyph. 228 CGPoint renderOrigin; 229 renderOrigin.x = -characterInfo.xOrigin; 230 renderOrigin.y = -characterInfo.yOrigin; 231 232#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 233 CTFontDrawGlyphs( mFontRef, &characterGlyph, &renderOrigin, 1, bitmapContext ); 234#else 235 CGFontRef cgFont = CTFontCopyGraphicsFont(mFontRef, NULL); 236 CGContextSetFont(bitmapContext, cgFont); 237 CGContextSetFontSize(bitmapContext, CTFontGetSize(mFontRef)); 238 CGContextShowGlyphsAtPositions(bitmapContext, &characterGlyph, &renderOrigin, 1); 239 CFRelease(cgFont); 240#endif 241 242 243#if 0 244 Con::printf("Width:%f, Height:%f, OriginX:%f, OriginY:%f", 245 characterBounds.size.width, 246 characterBounds.size.height, 247 characterBounds.origin.x, 248 characterBounds.origin.y ); 249#endif 250 251 // Adjust the y origin for the glyph size. 252 characterInfo.yOrigin += characterInfo.height;// + mHeight; 253 254 // Release the bitmap context. 255 CGContextRelease( bitmapContext ); 256 257 // Return character information. 258 return characterInfo; 259} 260