/************************************************************** * * 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 #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 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(pData)->maPolygon; const int nPointCount = rPolygon.count(); switch( pElement->type ) { case kCGPathElementCloseSubpath: case kCGPathElementMoveToPoint: if( nPointCount > 0 ) { static_cast(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( 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(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; } // =======================================================================