//----------------------------------------------------------------------------- // 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 #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& 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; }