macFont.mm 9.4 KB

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