blob: 6131b2fcdd686ba176c5ab712f148adfa57c21e3 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
#include "impfont.hxx"
#include "outfont.hxx"
#include "sallayout.hxx"
#include "aqua/salinst.h"
#include "aqua/saldata.hxx"
#include "aqua/salgdi.h"
#include "ctfonts.hxx"
#include "basegfx/polygon/b2dpolygon.hxx"
#include "basegfx/matrix/b2dhommatrix.hxx"
#ifndef DISABLE_CORETEXT_DYNLOAD
#include <dlfcn.h>
#endif
// =======================================================================
// CoreText specific physically available font face
class CTFontData
: public ImplMacFontData
{
public:
explicit CTFontData( const ImplDevFontAttributes&, sal_IntPtr nFontId );
virtual ~CTFontData( void );
virtual ImplFontData* Clone( void ) const;
virtual ImplMacTextStyle* CreateMacTextStyle( const ImplFontSelectData& ) const;
virtual ImplFontEntry* CreateFontInstance( /*const*/ ImplFontSelectData& ) const;
virtual int GetFontTable( const char pTagName[5], unsigned char* ) const;
};
// =======================================================================
class CTFontList
: public SystemFontList
{
public:
explicit CTFontList( void );
virtual ~CTFontList( void );
bool Init( void );
void AddFont( CTFontData* );
virtual void AnnounceFonts( ImplDevFontList& ) const;
virtual ImplMacFontData* GetFontDataFromId( sal_IntPtr ) const;
private:
CTFontCollectionRef mpCTFontCollection;
CFArrayRef mpCTFontArray;
typedef std::hash_map<sal_IntPtr,CTFontData*> CTFontContainer;
CTFontContainer maFontContainer;
};
// =======================================================================
CTTextStyle::CTTextStyle( const ImplFontSelectData& rFSD )
: ImplMacTextStyle( rFSD )
, mpStyleDict( NULL )
{
mpFontData = (CTFontData*)rFSD.mpFontData;
const ImplFontSelectData* const pReqFont = &rFSD;
double fScaledFontHeight = pReqFont->mfExactHeight;
#if 0 // TODO: does CoreText need font size limiting???
static const float fMaxFontHeight = 144.0; // TODO: is there a limit for CoreText?
if( fScaledFontHeight > fMaxFontHeight )
{
mfFontScale = fScaledFontHeight / fMaxFontHeight;
fScaledFontHeight = fMaxFontHeight;
}
#endif
// convert font rotation to radian
mfFontRotation = pReqFont->mnOrientation * (M_PI / 1800.0);
// handle font stretching if any
const CGAffineTransform* pMatrix = NULL;
CGAffineTransform aMatrix;
if( (pReqFont->mnWidth != 0) && (pReqFont->mnWidth != pReqFont->mnHeight) )
{
mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight;
aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F );
pMatrix = &aMatrix;
}
// handle emulation of italic/oblique styles if requested and the font doesn't provide them
if( ((pReqFont->meItalic == ITALIC_NORMAL) || (pReqFont->meItalic == ITALIC_OBLIQUE))
&& (mpFontData->meItalic == ITALIC_NONE))
{
if( !pMatrix)
pMatrix = &(aMatrix = CGAffineTransformIdentity);
aMatrix = CGAffineTransformConcat(aMatrix, CGAffineTransformMake( 1, 0, 0.375F, 1, 0, 0));
}
// create the style object for CoreText font attributes
static const CFIndex nMaxDictSize = 16; // TODO: does this really suffice?
mpStyleDict = CFDictionaryCreateMutable( NULL, nMaxDictSize,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
// set some default styles: no kerning, regular ligatures
static const CGFloat fValZero = 0.0;
CFNumberRef pCFFloatNumZero = CFNumberCreate( NULL, kCFNumberFloatType, &fValZero );
CFDictionarySetValue( mpStyleDict, kCTKernAttributeName, pCFFloatNumZero );
CFRelease( pCFFloatNumZero);
static const int nValOne = 1;
CFNumberRef pCFIntNumOne = CFNumberCreate( NULL, kCFNumberIntType, &nValOne );
CFDictionarySetValue( mpStyleDict, kCTLigatureAttributeName, pCFIntNumOne );
CFRelease( pCFIntNumOne);
CFBooleanRef pCFVertBool = pReqFont->mbVertical ? kCFBooleanTrue : kCFBooleanFalse;
CFDictionarySetValue( mpStyleDict, kCTVerticalFormsAttributeName, pCFVertBool );
CTFontDescriptorRef pFontDesc = (CTFontDescriptorRef)mpFontData->GetFontId();
CTFontRef pNewCTFont = CTFontCreateWithFontDescriptor( pFontDesc, fScaledFontHeight, pMatrix );
CFDictionarySetValue( mpStyleDict, kCTFontAttributeName, pNewCTFont );
CFRelease( pNewCTFont);
// allow delayed setting the font color, i.e. after the text layout
CFDictionarySetValue( mpStyleDict, kCTForegroundColorFromContextAttributeName, kCFBooleanTrue );
// handle emulation of bold styles if requested and the font that doesn't provide them
if( (pReqFont->meWeight > WEIGHT_MEDIUM)
&& (mpFontData->meWeight <= WEIGHT_MEDIUM)
&& (mpFontData->meWeight != WEIGHT_DONTKNOW))
{
const int nBoldFactor = -lrint( (3.5F * pReqFont->meWeight) / mpFontData->meWeight);
CFNumberRef pCFIntBold = CFNumberCreate( NULL, kCFNumberIntType, &nBoldFactor);
CFDictionarySetValue( mpStyleDict, kCTStrokeWidthAttributeName, pCFIntBold);
}
#if 0 // LastResort is implicit in CoreText's font cascading
const void* aGFBDescriptors[] = { CTFontDescriptorCreateWithNameAndSize( CFSTR("LastResort"), 0) }; // TODO: use the full GFB list
const int nGfbCount = sizeof(aGFBDescriptors) / sizeof(*aGFBDescriptors);
CFArrayRef pGfbList = CFArrayCreate( NULL, aGFBDescriptors, nGfbCount, &kCFTypeArrayCallBacks);
CFDictionaryAddValue( mpStyleDict, kCTFontCascadeListAttribute, pGfbList);
CFRelease( pGfbList);
#endif
}
// -----------------------------------------------------------------------
CTTextStyle::~CTTextStyle( void )
{
if( mpStyleDict )
CFRelease( mpStyleDict );
}
// -----------------------------------------------------------------------
void CTTextStyle::GetFontMetric( float fDPIY, ImplFontMetricData& rMetric ) const
{
// get the matching CoreText font handle
// TODO: is it worth it to cache the CTFontRef in SetFont() and reuse it here?
CTFontRef aCTFontRef = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName );
const double fPixelSize = (mfFontScale * fDPIY);
const CGFloat fAscent = CTFontGetAscent( aCTFontRef );
const CGFloat fCapHeight = CTFontGetCapHeight( aCTFontRef );
rMetric.mnAscent = lrint( fAscent * fPixelSize);
rMetric.mnDescent = lrint( CTFontGetDescent( aCTFontRef ) * fPixelSize);
rMetric.mnExtLeading = lrint( CTFontGetLeading( aCTFontRef ) * fPixelSize);
rMetric.mnIntLeading = lrint( (fAscent - fCapHeight) * fPixelSize);
// since ImplFontMetricData::mnWidth is only used for stretching/squeezing fonts
// setting this width to the pixel height of the fontsize is good enough
// it also makes the calculation of the stretch factor simple
rMetric.mnWidth = lrint( CTFontGetSize( aCTFontRef ) * fPixelSize * mfFontStretch);
// all CoreText fonts are scalable
rMetric.mbScalableFont = true;
// TODO: check if any kerning is supported
rMetric.mbKernableFont = true;
}
// -----------------------------------------------------------------------
bool CTTextStyle::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect ) const
{
const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
CGGlyph nCGGlyph = aGlyphId & GF_IDXMASK; // NOTE: CoreText handles glyph fallback itself
CTFontRef aCTFontRef = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName );
const CTFontOrientation aFontOrientation = kCTFontDefaultOrientation; // TODO: horz/vert
const CGRect aCGRect = rCT.FontGetBoundingRectsForGlyphs( aCTFontRef, aFontOrientation, &nCGGlyph, NULL, 1 );
rRect.Left() = lrint( mfFontScale * aCGRect.origin.x );
rRect.Top() = lrint( mfFontScale * aCGRect.origin.y );
rRect.Right() = lrint( mfFontScale * (aCGRect.origin.x + aCGRect.size.width) );
rRect.Bottom() = lrint( mfFontScale * (aCGRect.origin.y + aCGRect.size.height) );
return true;
}
// -----------------------------------------------------------------------
// callbacks from CTFontCreatePathForGlyph+CGPathApply for GetGlyphOutline()
struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; };
static void MyCGPathApplierFunc( void* pData, const CGPathElement* pElement )
{
basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
const int nPointCount = rPolygon.count();
switch( pElement->type )
{
case kCGPathElementCloseSubpath:
case kCGPathElementMoveToPoint:
if( nPointCount > 0 ) {
static_cast<GgoData*>(pData)->mpPolyPoly->append( rPolygon );
rPolygon.clear();
}
// fall through for kCGPathElementMoveToPoint:
if( pElement->type != kCGPathElementMoveToPoint )
break;
case kCGPathElementAddLineToPoint:
rPolygon.append( basegfx::B2DPoint( +pElement->points[0].x, -pElement->points[0].y ) );
break;
case kCGPathElementAddCurveToPoint:
rPolygon.append( basegfx::B2DPoint( +pElement->points[2].x, -pElement->points[2].y ) );
rPolygon.setNextControlPoint( nPointCount-1, basegfx::B2DPoint( pElement->points[0].x, -pElement->points[0].y ) );
rPolygon.setPrevControlPoint( nPointCount+0, basegfx::B2DPoint( pElement->points[1].x, -pElement->points[1].y ) );
break;
case kCGPathElementAddQuadCurveToPoint: {
const basegfx::B2DPoint aStartPt = rPolygon.getB2DPoint( nPointCount-1 );
const basegfx::B2DPoint aCtrPt1( (aStartPt.getX() + 2* pElement->points[0].x) / 3.0,
(aStartPt.getY() - 2 * pElement->points[0].y) / 3.0 );
const basegfx::B2DPoint aCtrPt2( (+2 * +pElement->points[0].x + pElement->points[1].x) / 3.0,
(-2 * pElement->points[0].y - pElement->points[1].y) / 3.0 );
rPolygon.append( basegfx::B2DPoint( +pElement->points[1].x, -pElement->points[1].y ) );
rPolygon.setNextControlPoint( nPointCount-1, aCtrPt1 );
rPolygon.setPrevControlPoint( nPointCount+0, aCtrPt2 );
} break;
}
}
bool CTTextStyle::GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& rResult ) const
{
rResult.clear();
const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
// TODO: GF_FONTMASK if using non-native glyph fallback
CGGlyph nCGGlyph = aGlyphId & GF_IDXMASK;
CTFontRef pCTFont = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName );
CGPathRef xPath = rCT.FontCreatePathForGlyph( pCTFont, nCGGlyph, NULL );
GgoData aGgoData;
aGgoData.mpPolyPoly = &rResult;
CGPathApply( xPath, (void*)&aGgoData, MyCGPathApplierFunc );
#if 0 // TODO: does OSX ensure that the last polygon is always closed?
const CGPathElement aClosingElement = { kCGPathElementCloseSubpath, NULL };
MyCGPathApplierFunc( (void*)&aGgoData, &aClosingElement );
#endif
// apply the font scale
if( mfFontScale != 1.0 ) {
basegfx::B2DHomMatrix aScale;
aScale.scale( +mfFontScale, +mfFontScale );
rResult.transform( aScale );
}
return true;
}
// =======================================================================
CTFontData::CTFontData( const ImplDevFontAttributes& rDFA, sal_IntPtr nFontId )
: ImplMacFontData( rDFA, nFontId )
{}
// -----------------------------------------------------------------------
CTFontData::~CTFontData( void )
{
// TODO: any resources to release?
}
// -----------------------------------------------------------------------
ImplFontData* CTFontData::Clone( void ) const
{
return new CTFontData( *this);
}
// -----------------------------------------------------------------------
ImplMacTextStyle* CTFontData::CreateMacTextStyle( const ImplFontSelectData& rFSD ) const
{
return new CTTextStyle( rFSD);
}
// -----------------------------------------------------------------------
ImplFontEntry* CTFontData::CreateFontInstance( /*const*/ ImplFontSelectData& rFSD ) const
{
return new ImplFontEntry( rFSD);
}
// -----------------------------------------------------------------------
int CTFontData::GetFontTable( const char pTagName[5], unsigned char* pResultBuf ) const
{
DBG_ASSERT( pTagName[4]=='\0', "CTFontData::GetFontTable with invalid tagname!\n" );
const CTFontTableTag nTagCode = (pTagName[0]<<24) + (pTagName[1]<<16) + (pTagName[2]<<8) + (pTagName[3]<<0);
// get the raw table length
CTFontDescriptorRef pFontDesc = reinterpret_cast<CTFontDescriptorRef>( GetFontId());
CTFontRef rCTFont = CTFontCreateWithFontDescriptor( pFontDesc, 0.0, NULL);
CFDataRef pDataRef = CTFontCopyTable( rCTFont, nTagCode, kCTFontTableOptionExcludeSynthetic);
CFRelease( rCTFont);
if( !pDataRef)
return 0;
const CFIndex nByteLength = CFDataGetLength( pDataRef);
// get the raw table data if requested
if( pResultBuf && (nByteLength > 0))
{
const CFRange aFullRange = CFRangeMake( 0, nByteLength);
CFDataGetBytes( pDataRef, aFullRange, (UInt8*)pResultBuf);
}
CFRelease( pDataRef);
return (int)nByteLength;
}
// =======================================================================
static void CTFontEnumCallBack( const void* pValue, void* pContext )
{
CTFontDescriptorRef pFD = static_cast<CTFontDescriptorRef>(pValue);
// all CoreText fonts are device fonts that can rotate just fine
ImplDevFontAttributes rDFA;
rDFA.mbOrientation = true;
rDFA.mbDevice = true;
rDFA.mnQuality = 0;
// reset the font attributes
rDFA.meFamily = FAMILY_DONTKNOW;
rDFA.mePitch = PITCH_VARIABLE;
rDFA.meWidthType = WIDTH_NORMAL;
rDFA.meWeight = WEIGHT_NORMAL;
rDFA.meItalic = ITALIC_NONE;
rDFA.mbSymbolFlag = false;
// all scalable fonts on this platform are subsettable
rDFA.mbEmbeddable = false;
rDFA.mbSubsettable = true;
// get font name
// TODO: use kCTFontDisplayNameAttribute instead???
CFStringRef pFamilyName = (CFStringRef)CTFontDescriptorCopyAttribute( pFD, kCTFontFamilyNameAttribute );
rDFA.maName = GetOUString( pFamilyName );
// get font style
CFStringRef pStyleName = (CFStringRef)CTFontDescriptorCopyAttribute( pFD, kCTFontStyleNameAttribute );
rDFA.maStyleName = GetOUString( pStyleName );
// get font-enabled status
int bFontEnabled = FALSE;
CFNumberRef pFontEnabled = (CFNumberRef)CTFontDescriptorCopyAttribute( pFD, kCTFontEnabledAttribute );
CFNumberGetValue( pFontEnabled, kCFNumberIntType, &bFontEnabled );
// get font attributes
CFDictionaryRef pAttrDict = (CFDictionaryRef)CTFontDescriptorCopyAttribute( pFD, kCTFontTraitsAttribute );
// get symbolic trait
// TODO: use other traits such as MonoSpace/Condensed/Expanded or Vertical too
SInt64 nSymbolTrait = 0;
CFNumberRef pSymbolNum = NULL;
if( CFDictionaryGetValueIfPresent( pAttrDict, kCTFontSymbolicTrait, (const void**)&pSymbolNum ) ) {
CFNumberGetValue( pSymbolNum, kCFNumberSInt64Type, &nSymbolTrait );
rDFA.mbSymbolFlag = ((nSymbolTrait & kCTFontClassMaskTrait) == kCTFontSymbolicClass);
}
// get the font weight
double fWeight = 0;
CFNumberRef pWeightNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontWeightTrait );
CFNumberGetValue( pWeightNum, kCFNumberDoubleType, &fWeight );
int nInt = WEIGHT_NORMAL;
if( fWeight > 0 ) {
nInt = rint(WEIGHT_NORMAL + fWeight * ((WEIGHT_BLACK - WEIGHT_NORMAL)/0.68));
if( nInt > WEIGHT_BLACK )
nInt = WEIGHT_BLACK;
} else if( fWeight < 0 ) {
nInt = rint(WEIGHT_NORMAL + fWeight * ((WEIGHT_NORMAL - WEIGHT_THIN)/0.9));
if( nInt < WEIGHT_THIN )
nInt = WEIGHT_THIN;
}
rDFA.meWeight = (FontWeight)nInt;
// get the font slant
double fSlant = 0;
CFNumberRef pSlantNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontSlantTrait );
CFNumberGetValue( pSlantNum, kCFNumberDoubleType, &fSlant );
if( fSlant >= 0.035 )
rDFA.meItalic = ITALIC_NORMAL;
// get width trait
double fWidth = 0;
CFNumberRef pWidthNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontWidthTrait );
CFNumberGetValue( pWidthNum, kCFNumberDoubleType, &fWidth );
nInt = WIDTH_NORMAL;
if( fWidth > 0 ) {
nInt = rint( WIDTH_NORMAL + fWidth * ((WIDTH_ULTRA_EXPANDED - WIDTH_NORMAL)/0.4));
if( nInt > WIDTH_ULTRA_EXPANDED )
nInt = WIDTH_ULTRA_EXPANDED;
} else if( fWidth < 0 ) {
nInt = rint( WIDTH_NORMAL + fWidth * ((WIDTH_NORMAL - WIDTH_ULTRA_CONDENSED)/0.5));
if( nInt < WIDTH_ULTRA_CONDENSED )
nInt = WIDTH_ULTRA_CONDENSED;
}
rDFA.meWidthType = (FontWidth)nInt;
// release the attribute dict that we had copied
CFRelease( pAttrDict );
// TODO? also use the HEAD table if available to get more attributes
// CFDataRef CTFontCopyTable( CTFontRef, kCTFontTableHead, /*kCTFontTableOptionNoOptions*/kCTFontTableOptionExcludeSynthetic );
#if (OSL_DEBUG_LEVEL >= 1)
// update font attributes using the font's postscript name
ImplDevFontAttributes rDFA2;
CTFontRef pFont = CTFontCreateWithFontDescriptor( pFD, 0.0, NULL );
CFStringRef pPSName = CTFontCopyPostScriptName( pFont );
const String aPSName = GetOUString( pPSName );
rDFA2.mbSymbolFlag = false;
rDFA2.mePitch = PITCH_VARIABLE;
rDFA2.meWidthType = WIDTH_NORMAL;
rDFA2.meWeight = WEIGHT_NORMAL;
rDFA2.meItalic = ITALIC_NONE;
UpdateAttributesFromPSName( aPSName, rDFA2 );
CFRelease( pPSName );
CFRelease( pFont );
// show the font details and compare the CTFontDescriptor vs. PSName traits
char cMatch = (rDFA.mbSymbolFlag==rDFA2.mbSymbolFlag);
cMatch &= (rDFA.meWeight==rDFA2.meWeight);
cMatch &= ((rDFA.meItalic==ITALIC_NONE) == (rDFA2.meItalic==ITALIC_NONE));
cMatch &= (rDFA.meWidthType==rDFA2.meWidthType);
cMatch = cMatch ? '.' : '#';
char aFN[256], aSN[256];
CFStringGetCString( pFamilyName, aFN, sizeof(aFN), kCFStringEncodingUTF8 );
CFStringGetCString( pStyleName, aSN, sizeof(aSN), kCFStringEncodingUTF8 );
const ByteString aPSCName( aPSName, RTL_TEXTENCODING_UTF8 );
const char* aPN = aPSCName.GetBuffer();
printf("\tCTFont_%d%x%d%d_%c_%d%x%d%d ena=%d s=%02d b=%+.2f i=%+.2f w=%+.2f (\"%s\", \"%s\", \"%s\")\n",
(int)rDFA.mbSymbolFlag,(int)rDFA.meWeight,(int)rDFA.meItalic,(int)rDFA.meWidthType,
cMatch,
(int)rDFA2.mbSymbolFlag,(int)rDFA2.meWeight,(int)rDFA2.meItalic,(int)rDFA2.meWidthType,
bFontEnabled,
(int)(nSymbolTrait>>kCTFontClassMaskShift),fWeight,fSlant,fWidth,aFN,aSN,aPN);
#endif // (OSL_DEBUG_LEVEL >= 1)
if( bFontEnabled)
{
const sal_IntPtr nFontId = (sal_IntPtr)pValue;
CTFontData* pFontData = new CTFontData( rDFA, nFontId );
CTFontList* pFontList = (CTFontList*)pContext;
pFontList->AddFont( pFontData );
}
}
// =======================================================================
CTFontList::CTFontList()
: mpCTFontCollection( NULL )
, mpCTFontArray( NULL )
{}
// -----------------------------------------------------------------------
CTFontList::~CTFontList()
{
CTFontContainer::const_iterator it = maFontContainer.begin();
for(; it != maFontContainer.end(); ++it )
delete (*it).second;
maFontContainer.clear();
if( mpCTFontArray )
CFRelease( mpCTFontArray );
if( mpCTFontCollection )
CFRelease( mpCTFontCollection );
}
// -----------------------------------------------------------------------
void CTFontList::AddFont( CTFontData* pFontData )
{
sal_IntPtr nFontId = pFontData->GetFontId();
maFontContainer[ nFontId ] = pFontData;
}
// -----------------------------------------------------------------------
void CTFontList::AnnounceFonts( ImplDevFontList& rFontList ) const
{
CTFontContainer::const_iterator it = maFontContainer.begin();
for(; it != maFontContainer.end(); ++it )
rFontList.Add( (*it).second->Clone() );
}
// -----------------------------------------------------------------------
ImplMacFontData* CTFontList::GetFontDataFromId( sal_IntPtr nFontId ) const
{
CTFontContainer::const_iterator it = maFontContainer.find( nFontId );
if( it == maFontContainer.end() )
return NULL;
return (*it).second;
}
// -----------------------------------------------------------------------
bool CTFontList::Init( void )
{
#ifndef DISABLE_CORETEXT_DYNLOAD
// check availability of the CoreText API
const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
if( !rCT.IsActive() )
return false;
#endif // DISABLE_CORETEXT_DYNLOAD
// enumerate available system fonts
static const int nMaxDictEntries = 8;
CFMutableDictionaryRef pCFDict = CFDictionaryCreateMutable( NULL,
nMaxDictEntries, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
CFDictionaryAddValue( pCFDict, kCTFontCollectionRemoveDuplicatesOption, kCFBooleanTrue );
mpCTFontCollection = rCT.FontCollectionCreateFromAvailableFonts( pCFDict );
CFRelease( pCFDict );
mpCTFontArray = rCT.FontCollectionCreateMatchingFontDescriptors( mpCTFontCollection );
const int nFontCount = CFArrayGetCount( mpCTFontArray );
const CFRange aFullRange = CFRangeMake( 0, nFontCount );
CFArrayApplyFunction( mpCTFontArray, aFullRange, CTFontEnumCallBack, this );
return true;
}
// =======================================================================
#ifndef DISABLE_CORETEXT_DYNLOAD
DynCoreTextSyms::DynCoreTextSyms( void )
{
mbIsActive = false;
// check if CoreText has been explicitely disabled
const char* pEnvStr = getenv( "SAL_DISABLE_CORETEXT");
if( pEnvStr && (pEnvStr[0] != '0') )
return;
// check CoreText version
GetCoreTextVersion = (uint32_t(*)(void))dlsym( RTLD_DEFAULT, "CTGetCoreTextVersion");
if( !GetCoreTextVersion) return;
const uint32_t nCTVersion = GetCoreTextVersion();
static const uint32_t mykCTVersionNumber10_5 = 0x00020000;
if( nCTVersion < mykCTVersionNumber10_5)
return;
// load CoreText symbols dynamically
LineGetTrailingWhitespaceWidth = (double(*)(CTLineRef))dlsym( RTLD_DEFAULT, "CTLineGetTrailingWhitespaceWidth");
if( !LineGetTrailingWhitespaceWidth) return;
LineCreateJustifiedLine = (CTLineRef(*)(CTLineRef,CGFloat,double))dlsym( RTLD_DEFAULT, "CTLineCreateJustifiedLine");
if( !LineCreateJustifiedLine) return;
LineGetOffsetForStringIndex = (CGFloat(*)(CTLineRef,CFIndex,CGFloat*))dlsym( RTLD_DEFAULT, "CTLineGetOffsetForStringIndex");
if( !LineGetOffsetForStringIndex) return;
LineGetGlyphRuns = (CFArrayRef(*)(CTLineRef))dlsym( RTLD_DEFAULT, "CTLineGetGlyphRuns");
if( !LineGetGlyphRuns) return;
RunGetGlyphCount = (CFIndex(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetGlyphCount");
if( !RunGetGlyphCount) return;
RunGetGlyphsPtr = (const CGGlyph*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetGlyphsPtr");
if( !RunGetGlyphsPtr) return;
RunGetPositionsPtr = (const CGPoint*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetPositionsPtr");
if( !RunGetPositionsPtr) return;
RunGetAdvancesPtr = (const CGSize*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetAdvancesPtr");
if( !RunGetAdvancesPtr) return;
RunGetStringIndicesPtr = (const CFIndex*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetStringIndicesPtr");
if( !RunGetStringIndicesPtr) return;
FontCollectionCreateFromAvailableFonts = (CTFontCollectionRef(*)(CFDictionaryRef))dlsym( RTLD_DEFAULT, "CTFontCollectionCreateFromAvailableFonts");
if( !FontCollectionCreateFromAvailableFonts) return;
FontCollectionCreateMatchingFontDescriptors = (CFArrayRef(*)(CTFontCollectionRef))dlsym( RTLD_DEFAULT, "CTFontCollectionCreateMatchingFontDescriptors");
if( !FontCollectionCreateMatchingFontDescriptors) return;
FontCreatePathForGlyph = (CGPathRef(*)(CTFontRef,CGGlyph,const CGAffineTransform*))dlsym( RTLD_DEFAULT, "CTFontCreatePathForGlyph");
if( !FontCreatePathForGlyph) return;
FontGetBoundingRectsForGlyphs = (CGRect(*)(CTFontRef,CTFontOrientation,CGGlyph*,CGRect*,CFIndex))dlsym( RTLD_DEFAULT, "CTFontGetBoundingRectsForGlyphs");
if( !FontGetBoundingRectsForGlyphs) return;
mbIsActive = true;
}
// -----------------------------------------------------------------------
const DynCoreTextSyms& DynCoreTextSyms::get( void )
{
static DynCoreTextSyms aCT;
return aCT;
}
#endif // DISABLE_CORETEXT_DYNLOAD
// =======================================================================
SystemFontList* GetCoretextFontList( void )
{
CTFontList* pList = new CTFontList();
if( !pList->Init() ) {
delete pList;
return NULL;
}
return pList;
}
// =======================================================================