123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #import <Cocoa/Cocoa.h>
- #import "platform/platform.h"
- #import "core/util/tVector.h"
- #import "math/mMathFn.h"
- #import "platformMac/macFont.h"
- #import "core/stringTable.h"
- #import "core/strings/unicode.h"
- #import "console/console.h"
- //------------------------------------------------------------------------------
- PlatformFont* createPlatformFont( const char* name, dsize_t size, U32 charset )
- {
- PlatformFont* pFont = new OSXFont();
-
- if ( pFont->create(name, size, charset) )
- return pFont;
-
- delete pFont;
-
- return NULL;
- }
- //------------------------------------------------------------------------------
- void PlatformFont::enumeratePlatformFonts( Vector<StringTableEntry>& fonts, UTF16 *fontFamily )
- {
- // Fetch available fonts.
- NSArray* availableFonts = [[NSFontManager sharedFontManager] availableFontNamesWithTraits:0];
-
- // Enumerate font names.
- for (id fontName in availableFonts)
- {
- fonts.push_back( StringTable->insert( [fontName UTF8String] ) );
- }
-
- // Release font name.
- [availableFonts release];
- }
- //------------------------------------------------------------------------------
- OSXFont::OSXFont()
- {
- // Reset the rendering color-space.
- mColorSpace = NULL;
- }
- //------------------------------------------------------------------------------
- OSXFont::~OSXFont()
- {
- // Destroy the rendering color-space.
- CGColorSpaceRelease( mColorSpace );
- }
- //------------------------------------------------------------------------------
- bool OSXFont::create( const char* name, dsize_t size, U32 charset )
- {
- // Sanity!
- AssertFatal( name != NULL, "Cannot create a NULL font name." );
-
- bool doBold = false;
- bool doItalic = false;
- String nameStr = name;
- nameStr = nameStr.trim();
- bool haveModifier;
- do
- {
- haveModifier = false;
- if( nameStr.compare( "Bold", 4, String::NoCase | String::Right ) == 0 )
- {
- doBold = true;
- nameStr = nameStr.substr( 0, nameStr.length() - 4 ).trim();
- haveModifier = true;
- }
- if( nameStr.compare( "Italic", 6, String::NoCase | String::Right ) == 0 )
- {
- doItalic = true;
- nameStr = nameStr.substr( 0, nameStr.length() - 6 ).trim();
- haveModifier = true;
- }
- }
- while( haveModifier );
- // Generate compatible font name.
- NSString* fontName = [NSString stringWithUTF8String: nameStr.utf8()];
-
- // Sanity!
- if ( !fontName )
- {
- Con::errorf("Could not handle font name of '%s'.", name );
- return false;
- }
-
- NSMutableDictionary* fontAttributes = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- fontName, (NSString*)kCTFontFamilyNameAttribute,
- [NSNumber numberWithFloat: (float)size], (NSString*)kCTFontSizeAttribute,
- nil];
-
- CTFontSymbolicTraits traits = 0x0;
- if (doBold)
- traits |= kCTFontBoldTrait;
- if (doItalic)
- traits |= kCTFontItalicTrait;
-
- CTFontDescriptorRef descriptor =
- CTFontDescriptorCreateWithAttributes((CFDictionaryRef)fontAttributes);
-
- mFontRef = CTFontCreateWithFontDescriptor(descriptor, 0.0, NULL);
- CFRelease(descriptor);
-
- // Sanity!
- if ( !mFontRef )
- {
- Con::errorf( "Could not generate a font reference to font name '%s' of size '%d'", name, size );
- return false;
- }
-
- // Apply font traits if we have any by creating a copy of the font
- if (traits != 0x0)
- mFontRef = CTFontCreateCopyWithSymbolicTraits(mFontRef, (float)size, NULL, traits, traits);
-
- // Fetch font metrics.
- CGFloat ascent = CTFontGetAscent( mFontRef );
- CGFloat descent = CTFontGetDescent( mFontRef );
-
- // Set baseline.
- mBaseline = (U32)mRound(ascent);
-
- // Set height.
- mHeight = (U32)mRound( ascent + descent );
-
- // Create a gray-scale color-space.
- mColorSpace = CGColorSpaceCreateDeviceGray();
-
- // Return status.
- return true;
- }
- //------------------------------------------------------------------------------
- bool OSXFont::isValidChar( const UTF8* str ) const
- {
- // since only low order characters are invalid, and since those characters
- // are single codeunits in UTF8, we can safely cast here.
- return isValidChar((UTF16)*str);
- }
- //------------------------------------------------------------------------------
- bool OSXFont::isValidChar( const UTF16 character) const
- {
- // We cut out the ASCII control chars here. Only printable characters are valid.
- // 0x20 == 32 == space
- if( character < 0x20 )
- return false;
-
- return true;
- }
- //------------------------------------------------------------------------------
- PlatformFont::CharInfo& OSXFont::getCharInfo(const UTF8 *str) const
- {
- return getCharInfo( oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)) );
- }
- //------------------------------------------------------------------------------
- PlatformFont::CharInfo& OSXFont::getCharInfo(const UTF16 character) const
- {
- // Declare and clear out the CharInfo that will be returned.
- static PlatformFont::CharInfo characterInfo;
- dMemset(&characterInfo, 0, sizeof(characterInfo));
-
- // prep values for GFont::addBitmap()
- characterInfo.bitmapIndex = 0;
- characterInfo.xOffset = 0;
- characterInfo.yOffset = 0;
-
- CGGlyph characterGlyph;
- CGRect characterBounds;
- CGSize characterAdvances;
- UniChar unicodeCharacter = character;
-
- // Fetch font glyphs.
- if ( !CTFontGetGlyphsForCharacters( mFontRef, &unicodeCharacter, &characterGlyph, (CFIndex)1) )
- {
- // Sanity!
- //AssertFatal( false, "Cannot create font glyph." );
- Con::warnf("Font glyph is messed up. Some characters may render incorrectly.");
- }
-
- // Fetch glyph bounding box.
- CTFontGetBoundingRectsForGlyphs( mFontRef, kCTFontHorizontalOrientation, &characterGlyph, &characterBounds, (CFIndex)1 );
-
- // Fetch glyph advances.
- CTFontGetAdvancesForGlyphs( mFontRef, kCTFontHorizontalOrientation, &characterGlyph, &characterAdvances, (CFIndex)1 );
-
- // Set character metrics,
- characterInfo.xOrigin = (S32)mRound( characterBounds.origin.x );
- characterInfo.yOrigin = (S32)mRound( characterBounds.origin.y );
- characterInfo.width = (U32)mCeil( characterBounds.size.width ) + 2;
- characterInfo.height = (U32)mCeil( characterBounds.size.height ) + 2;
- characterInfo.xIncrement = (S32)mRound( characterAdvances.width );
-
- // Finish if character is undrawable.
- if ( characterInfo.width == 0 && characterInfo.height == 0 )
- return characterInfo;
-
- // Clamp character minimum width.
- if ( characterInfo.width == 0 )
- characterInfo.width = 2;
-
- if ( characterInfo.height == 0 )
- characterInfo.height = 1;
-
-
- // Allocate a bitmap surface.
- const U32 bitmapSize = characterInfo.width * characterInfo.height;
- characterInfo.bitmapData = new U8[bitmapSize];
- dMemset(characterInfo.bitmapData, 0x00, bitmapSize);
-
- // Create a bitmap context.
- CGContextRef bitmapContext = CGBitmapContextCreate( characterInfo.bitmapData, characterInfo.width, characterInfo.height, 8, characterInfo.width, mColorSpace, kCGImageAlphaNone );
-
- // Sanity!
- AssertFatal( bitmapContext != NULL, "Cannot create font context." );
-
- // Render font anti-aliased if font is arbitrarily small.
- CGContextSetShouldAntialias( bitmapContext, true);
- CGContextSetShouldSmoothFonts( bitmapContext, true);
- CGContextSetRenderingIntent( bitmapContext, kCGRenderingIntentAbsoluteColorimetric);
- CGContextSetInterpolationQuality( bitmapContext, kCGInterpolationNone);
- CGContextSetGrayFillColor( bitmapContext, 1.0, 1.0);
- CGContextSetTextDrawingMode( bitmapContext, kCGTextFill);
-
- // Draw glyph.
- CGPoint renderOrigin;
- renderOrigin.x = -characterInfo.xOrigin;
- renderOrigin.y = -characterInfo.yOrigin;
- CTFontDrawGlyphs( mFontRef, &characterGlyph, &renderOrigin, 1, bitmapContext );
-
- #if 0
- Con::printf("Width:%f, Height:%f, OriginX:%f, OriginY:%f",
- characterBounds.size.width,
- characterBounds.size.height,
- characterBounds.origin.x,
- characterBounds.origin.y );
- #endif
-
- // Adjust the y origin for the glyph size.
- characterInfo.yOrigin += characterInfo.height;// + mHeight;
-
- // Release the bitmap context.
- CGContextRelease( bitmapContext );
-
- // Return character information.
- return characterInfo;
- }
|