macFont.mm

Engine/source/platformMac/macFont.mm

More...

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