1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_vcl.hxx" 24 25 #include "impfont.hxx" 26 #include "outfont.hxx" 27 #include "sallayout.hxx" 28 29 #include "aqua/salinst.h" 30 #include "aqua/saldata.hxx" 31 #include "aqua/salgdi.h" 32 #include "ctfonts.hxx" 33 34 #include "basegfx/polygon/b2dpolygon.hxx" 35 #include "basegfx/matrix/b2dhommatrix.hxx" 36 37 #ifndef DISABLE_CORETEXT_DYNLOAD 38 #include <dlfcn.h> 39 #endif 40 41 // ======================================================================= 42 43 // CoreText specific physically available font face 44 class CTFontData 45 : public ImplMacFontData 46 { 47 public: 48 explicit CTFontData( const ImplDevFontAttributes&, sal_IntPtr nFontId ); 49 virtual ~CTFontData( void ); 50 virtual ImplFontData* Clone( void ) const; 51 52 virtual ImplMacTextStyle* CreateMacTextStyle( const ImplFontSelectData& ) const; 53 virtual ImplFontEntry* CreateFontInstance( /*const*/ ImplFontSelectData& ) const; 54 virtual int GetFontTable( const char pTagName[5], unsigned char* ) const; 55 }; 56 57 // ======================================================================= 58 59 class CTFontList 60 : public SystemFontList 61 { 62 public: 63 explicit CTFontList( void ); 64 virtual ~CTFontList( void ); 65 66 bool Init( void ); 67 void AddFont( CTFontData* ); 68 69 virtual void AnnounceFonts( ImplDevFontList& ) const; 70 virtual ImplMacFontData* GetFontDataFromId( sal_IntPtr ) const; 71 72 private: 73 CTFontCollectionRef mpCTFontCollection; 74 CFArrayRef mpCTFontArray; 75 76 typedef std::hash_map<sal_IntPtr,CTFontData*> CTFontContainer; 77 CTFontContainer maFontContainer; 78 }; 79 80 // ======================================================================= 81 82 CTTextStyle::CTTextStyle( const ImplFontSelectData& rFSD ) 83 : ImplMacTextStyle( rFSD ) 84 , mpStyleDict( NULL ) 85 { 86 mpFontData = (CTFontData*)rFSD.mpFontData; 87 const ImplFontSelectData* const pReqFont = &rFSD; 88 89 double fScaledFontHeight = pReqFont->mfExactHeight; 90 #if 0 // TODO: does CoreText need font size limiting??? 91 static const float fMaxFontHeight = 144.0; // TODO: is there a limit for CoreText? 92 if( fScaledFontHeight > fMaxFontHeight ) 93 { 94 mfFontScale = fScaledFontHeight / fMaxFontHeight; 95 fScaledFontHeight = fMaxFontHeight; 96 } 97 #endif 98 99 // convert font rotation to radian 100 mfFontRotation = pReqFont->mnOrientation * (M_PI / 1800.0); 101 102 // handle font stretching if any 103 const CGAffineTransform* pMatrix = NULL; 104 CGAffineTransform aMatrix; 105 if( (pReqFont->mnWidth != 0) && (pReqFont->mnWidth != pReqFont->mnHeight) ) 106 { 107 mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight; 108 aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F ); 109 pMatrix = &aMatrix; 110 } 111 112 // handle emulation of italic/oblique styles if requested and the font doesn't provide them 113 if( ((pReqFont->meItalic == ITALIC_NORMAL) || (pReqFont->meItalic == ITALIC_OBLIQUE)) 114 && (mpFontData->meItalic == ITALIC_NONE)) 115 { 116 if( !pMatrix) 117 pMatrix = &(aMatrix = CGAffineTransformIdentity); 118 aMatrix = CGAffineTransformConcat(aMatrix, CGAffineTransformMake( 1, 0, 0.375F, 1, 0, 0)); 119 } 120 121 // create the style object for CoreText font attributes 122 static const CFIndex nMaxDictSize = 16; // TODO: does this really suffice? 123 mpStyleDict = CFDictionaryCreateMutable( NULL, nMaxDictSize, 124 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); 125 126 // set some default styles: no kerning, regular ligatures 127 static const CGFloat fValZero = 0.0; 128 CFNumberRef pCFFloatNumZero = CFNumberCreate( NULL, kCFNumberFloatType, &fValZero ); 129 CFDictionarySetValue( mpStyleDict, kCTKernAttributeName, pCFFloatNumZero ); 130 CFRelease( pCFFloatNumZero); 131 static const int nValOne = 1; 132 CFNumberRef pCFIntNumOne = CFNumberCreate( NULL, kCFNumberIntType, &nValOne ); 133 CFDictionarySetValue( mpStyleDict, kCTLigatureAttributeName, pCFIntNumOne ); 134 CFRelease( pCFIntNumOne); 135 CFBooleanRef pCFVertBool = pReqFont->mbVertical ? kCFBooleanTrue : kCFBooleanFalse; 136 CFDictionarySetValue( mpStyleDict, kCTVerticalFormsAttributeName, pCFVertBool ); 137 138 CTFontDescriptorRef pFontDesc = (CTFontDescriptorRef)mpFontData->GetFontId(); 139 CTFontRef pNewCTFont = CTFontCreateWithFontDescriptor( pFontDesc, fScaledFontHeight, pMatrix ); 140 CFDictionarySetValue( mpStyleDict, kCTFontAttributeName, pNewCTFont ); 141 CFRelease( pNewCTFont); 142 143 // handle emulation of bold styles if requested and the font that doesn't provide them 144 if( (pReqFont->meWeight > WEIGHT_MEDIUM) 145 && (mpFontData->meWeight <= WEIGHT_MEDIUM) 146 && (mpFontData->meWeight != WEIGHT_DONTKNOW)) 147 { 148 const int nBoldFactor = -lrint( (3.5F * pReqFont->meWeight) / mpFontData->meWeight); 149 CFNumberRef pCFIntBold = CFNumberCreate( NULL, kCFNumberIntType, &nBoldFactor); 150 CFDictionarySetValue( mpStyleDict, kCTStrokeWidthAttributeName, pCFIntBold); 151 } 152 153 #if 0 // LastResort is implicit in CoreText's font cascading 154 const void* aGFBDescriptors[] = { CTFontDescriptorCreateWithNameAndSize( CFSTR("LastResort"), 0) }; // TODO: use the full GFB list 155 const int nGfbCount = sizeof(aGFBDescriptors) / sizeof(*aGFBDescriptors); 156 CFArrayRef pGfbList = CFArrayCreate( NULL, aGFBDescriptors, nGfbCount, &kCFTypeArrayCallBacks); 157 CFDictionaryAddValue( mpStyleDict, kCTFontCascadeListAttribute, pGfbList); 158 CFRelease( pGfbList); 159 #endif 160 } 161 162 // ----------------------------------------------------------------------- 163 164 CTTextStyle::~CTTextStyle( void ) 165 { 166 if( mpStyleDict ) 167 CFRelease( mpStyleDict ); 168 } 169 170 // ----------------------------------------------------------------------- 171 172 void CTTextStyle::GetFontMetric( float fDPIY, ImplFontMetricData& rMetric ) const 173 { 174 // get the matching CoreText font handle 175 // TODO: is it worth it to cache the CTFontRef in SetFont() and reuse it here? 176 CTFontRef aCTFontRef = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName ); 177 178 const double fPixelSize = (mfFontScale * fDPIY); 179 const CGFloat fAscent = CTFontGetAscent( aCTFontRef ); 180 const CGFloat fCapHeight = CTFontGetCapHeight( aCTFontRef ); 181 rMetric.mnAscent = lrint( fAscent * fPixelSize); 182 rMetric.mnDescent = lrint( CTFontGetDescent( aCTFontRef ) * fPixelSize); 183 rMetric.mnExtLeading = lrint( CTFontGetLeading( aCTFontRef ) * fPixelSize); 184 rMetric.mnIntLeading = lrint( (fAscent - fCapHeight) * fPixelSize); 185 186 // since ImplFontMetricData::mnWidth is only used for stretching/squeezing fonts 187 // setting this width to the pixel height of the fontsize is good enough 188 // it also makes the calculation of the stretch factor simple 189 rMetric.mnWidth = lrint( CTFontGetSize( aCTFontRef ) * fPixelSize * mfFontStretch); 190 191 // all CoreText fonts are scalable 192 rMetric.mbScalableFont = true; 193 // TODO: check if any kerning is supported 194 rMetric.mbKernableFont = true; 195 } 196 197 // ----------------------------------------------------------------------- 198 199 bool CTTextStyle::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect ) const 200 { 201 const DynCoreTextSyms& rCT = DynCoreTextSyms::get(); 202 CGGlyph nCGGlyph = aGlyphId & GF_IDXMASK; // NOTE: CoreText handles glyph fallback itself 203 CTFontRef aCTFontRef = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName ); 204 205 const CTFontOrientation aFontOrientation = kCTFontDefaultOrientation; // TODO: horz/vert 206 const CGRect aCGRect = rCT.FontGetBoundingRectsForGlyphs( aCTFontRef, aFontOrientation, &nCGGlyph, NULL, 1 ); 207 208 rRect.Left() = lrint( mfFontScale * aCGRect.origin.x ); 209 rRect.Top() = lrint( mfFontScale * aCGRect.origin.y ); 210 rRect.Right() = lrint( mfFontScale * (aCGRect.origin.x + aCGRect.size.width) ); 211 rRect.Bottom() = lrint( mfFontScale * (aCGRect.origin.y + aCGRect.size.height) ); 212 return true; 213 } 214 215 // ----------------------------------------------------------------------- 216 217 // callbacks from CTFontCreatePathForGlyph+CGPathApply for GetGlyphOutline() 218 struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; }; 219 220 static void MyCGPathApplierFunc( void* pData, const CGPathElement* pElement ) 221 { 222 basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon; 223 const int nPointCount = rPolygon.count(); 224 225 switch( pElement->type ) 226 { 227 case kCGPathElementCloseSubpath: 228 case kCGPathElementMoveToPoint: 229 if( nPointCount > 0 ) { 230 static_cast<GgoData*>(pData)->mpPolyPoly->append( rPolygon ); 231 rPolygon.clear(); 232 } 233 // fall through for kCGPathElementMoveToPoint: 234 if( pElement->type != kCGPathElementMoveToPoint ) 235 break; 236 case kCGPathElementAddLineToPoint: 237 rPolygon.append( basegfx::B2DPoint( +pElement->points[0].x, -pElement->points[0].y ) ); 238 break; 239 case kCGPathElementAddCurveToPoint: 240 rPolygon.append( basegfx::B2DPoint( +pElement->points[2].x, -pElement->points[2].y ) ); 241 rPolygon.setNextControlPoint( nPointCount-1, basegfx::B2DPoint( pElement->points[0].x, -pElement->points[0].y ) ); 242 rPolygon.setPrevControlPoint( nPointCount+0, basegfx::B2DPoint( pElement->points[1].x, -pElement->points[1].y ) ); 243 break; 244 case kCGPathElementAddQuadCurveToPoint: { 245 const basegfx::B2DPoint aStartPt = rPolygon.getB2DPoint( nPointCount-1 ); 246 const basegfx::B2DPoint aCtrPt1( (aStartPt.getX() + 2* pElement->points[0].x) / 3.0, 247 (aStartPt.getY() - 2 * pElement->points[0].y) / 3.0 ); 248 const basegfx::B2DPoint aCtrPt2( (+2 * +pElement->points[0].x + pElement->points[1].x) / 3.0, 249 (-2 * pElement->points[0].y - pElement->points[1].y) / 3.0 ); 250 rPolygon.append( basegfx::B2DPoint( +pElement->points[1].x, -pElement->points[1].y ) ); 251 rPolygon.setNextControlPoint( nPointCount-1, aCtrPt1 ); 252 rPolygon.setPrevControlPoint( nPointCount+0, aCtrPt2 ); 253 } break; 254 } 255 } 256 257 bool CTTextStyle::GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& rResult ) const 258 { 259 rResult.clear(); 260 261 const DynCoreTextSyms& rCT = DynCoreTextSyms::get(); 262 // TODO: GF_FONTMASK if using non-native glyph fallback 263 CGGlyph nCGGlyph = aGlyphId & GF_IDXMASK; 264 CTFontRef pCTFont = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName ); 265 CGPathRef xPath = rCT.FontCreatePathForGlyph( pCTFont, nCGGlyph, NULL ); 266 267 GgoData aGgoData; 268 aGgoData.mpPolyPoly = &rResult; 269 CGPathApply( xPath, (void*)&aGgoData, MyCGPathApplierFunc ); 270 #if 0 // TODO: does OSX ensure that the last polygon is always closed? 271 const CGPathElement aClosingElement = { kCGPathElementCloseSubpath, NULL }; 272 MyCGPathApplierFunc( (void*)&aGgoData, &aClosingElement ); 273 #endif 274 275 // apply the font scale 276 if( mfFontScale != 1.0 ) { 277 basegfx::B2DHomMatrix aScale; 278 aScale.scale( +mfFontScale, +mfFontScale ); 279 rResult.transform( aScale ); 280 } 281 282 return true; 283 } 284 285 // ----------------------------------------------------------------------- 286 287 void CTTextStyle::SetTextColor( const RGBAColor& rColor ) 288 { 289 #if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) 290 CGColorRef pCGColor = CGColorCreateGenericRGB( rColor.GetRed(), 291 rColor.GetGreen(), rColor.GetBlue(), rColor.GetAlpha() ); 292 #else // for builds on OSX 10.4 SDK 293 const CGColorSpaceRef pCGColorSpace = GetSalData()->mxRGBSpace; 294 CGColorRef pCGColor = CGColorCreate( pCGColorSpace, rColor.AsArray() ); 295 #endif 296 CFDictionarySetValue( mpStyleDict, kCTForegroundColorAttributeName, pCGColor ); 297 CFRelease( pCGColor); 298 } 299 300 // ======================================================================= 301 302 CTFontData::CTFontData( const ImplDevFontAttributes& rDFA, sal_IntPtr nFontId ) 303 : ImplMacFontData( rDFA, nFontId ) 304 {} 305 306 // ----------------------------------------------------------------------- 307 308 CTFontData::~CTFontData( void ) 309 { 310 // TODO: any resources to release? 311 } 312 313 // ----------------------------------------------------------------------- 314 315 ImplFontData* CTFontData::Clone( void ) const 316 { 317 return new CTFontData( *this); 318 } 319 320 // ----------------------------------------------------------------------- 321 322 ImplMacTextStyle* CTFontData::CreateMacTextStyle( const ImplFontSelectData& rFSD ) const 323 { 324 return new CTTextStyle( rFSD); 325 } 326 327 // ----------------------------------------------------------------------- 328 329 ImplFontEntry* CTFontData::CreateFontInstance( /*const*/ ImplFontSelectData& rFSD ) const 330 { 331 return new ImplFontEntry( rFSD); 332 } 333 334 // ----------------------------------------------------------------------- 335 336 int CTFontData::GetFontTable( const char pTagName[5], unsigned char* pResultBuf ) const 337 { 338 DBG_ASSERT( pTagName[4]=='\0', "CTFontData::GetFontTable with invalid tagname!\n" ); 339 340 const CTFontTableTag nTagCode = (pTagName[0]<<24) + (pTagName[1]<<16) + (pTagName[2]<<8) + (pTagName[3]<<0); 341 342 // get the raw table length 343 CTFontDescriptorRef pFontDesc = reinterpret_cast<CTFontDescriptorRef>( GetFontId()); 344 CTFontRef rCTFont = CTFontCreateWithFontDescriptor( pFontDesc, 0.0, NULL); 345 CFDataRef pDataRef = CTFontCopyTable( rCTFont, nTagCode, kCTFontTableOptionExcludeSynthetic); 346 CFRelease( rCTFont); 347 if( !pDataRef) 348 return 0; 349 350 const CFIndex nByteLength = CFDataGetLength( pDataRef); 351 352 // get the raw table data if requested 353 if( pResultBuf && (nByteLength > 0)) 354 { 355 const CFRange aFullRange = CFRangeMake( 0, nByteLength); 356 CFDataGetBytes( pDataRef, aFullRange, (UInt8*)pResultBuf); 357 } 358 359 CFRelease( pDataRef); 360 361 return (int)nByteLength; 362 } 363 364 // ======================================================================= 365 366 static void CTFontEnumCallBack( const void* pValue, void* pContext ) 367 { 368 CTFontDescriptorRef pFD = static_cast<CTFontDescriptorRef>(pValue); 369 370 // all CoreText fonts are device fonts that can rotate just fine 371 ImplDevFontAttributes rDFA; 372 rDFA.mbOrientation = true; 373 rDFA.mbDevice = true; 374 rDFA.mnQuality = 0; 375 376 // reset the font attributes 377 rDFA.meFamily = FAMILY_DONTKNOW; 378 rDFA.mePitch = PITCH_VARIABLE; 379 rDFA.meWidthType = WIDTH_NORMAL; 380 rDFA.meWeight = WEIGHT_NORMAL; 381 rDFA.meItalic = ITALIC_NONE; 382 rDFA.mbSymbolFlag = false; 383 384 // all scalable fonts on this platform are subsettable 385 rDFA.mbEmbeddable = false; 386 rDFA.mbSubsettable = true; 387 388 // get font name 389 // TODO: use kCTFontDisplayNameAttribute instead??? 390 CFStringRef pFamilyName = (CFStringRef)CTFontDescriptorCopyAttribute( pFD, kCTFontFamilyNameAttribute ); 391 rDFA.maName = GetOUString( pFamilyName ); 392 // get font style 393 CFStringRef pStyleName = (CFStringRef)CTFontDescriptorCopyAttribute( pFD, kCTFontStyleNameAttribute ); 394 rDFA.maStyleName = GetOUString( pStyleName ); 395 396 // get font-enabled status 397 int bFontEnabled = FALSE; 398 CFNumberRef pFontEnabled = (CFNumberRef)CTFontDescriptorCopyAttribute( pFD, kCTFontEnabledAttribute ); 399 CFNumberGetValue( pFontEnabled, kCFNumberIntType, &bFontEnabled ); 400 401 // get font attributes 402 CFDictionaryRef pAttrDict = (CFDictionaryRef)CTFontDescriptorCopyAttribute( pFD, kCTFontTraitsAttribute ); 403 404 // get symbolic trait 405 // TODO: use other traits such as MonoSpace/Condensed/Expanded or Vertical too 406 SInt64 nSymbolTrait = 0; 407 CFNumberRef pSymbolNum = NULL; 408 if( CFDictionaryGetValueIfPresent( pAttrDict, kCTFontSymbolicTrait, (const void**)&pSymbolNum ) ) { 409 CFNumberGetValue( pSymbolNum, kCFNumberSInt64Type, &nSymbolTrait ); 410 rDFA.mbSymbolFlag = ((nSymbolTrait & kCTFontClassMaskTrait) == kCTFontSymbolicClass); 411 } 412 413 // get the font weight 414 double fWeight = 0; 415 CFNumberRef pWeightNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontWeightTrait ); 416 CFNumberGetValue( pWeightNum, kCFNumberDoubleType, &fWeight ); 417 int nInt = WEIGHT_NORMAL; 418 if( fWeight > 0 ) { 419 nInt = rint(WEIGHT_NORMAL + fWeight * ((WEIGHT_BLACK - WEIGHT_NORMAL)/0.68)); 420 if( nInt > WEIGHT_BLACK ) 421 nInt = WEIGHT_BLACK; 422 } else if( fWeight < 0 ) { 423 nInt = rint(WEIGHT_NORMAL + fWeight * ((WEIGHT_NORMAL - WEIGHT_THIN)/0.9)); 424 if( nInt < WEIGHT_THIN ) 425 nInt = WEIGHT_THIN; 426 } 427 rDFA.meWeight = (FontWeight)nInt; 428 429 // get the font slant 430 double fSlant = 0; 431 CFNumberRef pSlantNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontSlantTrait ); 432 CFNumberGetValue( pSlantNum, kCFNumberDoubleType, &fSlant ); 433 if( fSlant >= 0.035 ) 434 rDFA.meItalic = ITALIC_NORMAL; 435 436 // get width trait 437 double fWidth = 0; 438 CFNumberRef pWidthNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontWidthTrait ); 439 CFNumberGetValue( pWidthNum, kCFNumberDoubleType, &fWidth ); 440 nInt = WIDTH_NORMAL; 441 if( fWidth > 0 ) { 442 nInt = rint( WIDTH_NORMAL + fWidth * ((WIDTH_ULTRA_EXPANDED - WIDTH_NORMAL)/0.4)); 443 if( nInt > WIDTH_ULTRA_EXPANDED ) 444 nInt = WIDTH_ULTRA_EXPANDED; 445 } else if( fWidth < 0 ) { 446 nInt = rint( WIDTH_NORMAL + fWidth * ((WIDTH_NORMAL - WIDTH_ULTRA_CONDENSED)/0.5)); 447 if( nInt < WIDTH_ULTRA_CONDENSED ) 448 nInt = WIDTH_ULTRA_CONDENSED; 449 } 450 rDFA.meWidthType = (FontWidth)nInt; 451 452 // release the attribute dict that we had copied 453 CFRelease( pAttrDict ); 454 455 // TODO? also use the HEAD table if available to get more attributes 456 // CFDataRef CTFontCopyTable( CTFontRef, kCTFontTableHead, /*kCTFontTableOptionNoOptions*/kCTFontTableOptionExcludeSynthetic ); 457 458 #if (OSL_DEBUG_LEVEL >= 1) 459 // update font attributes using the font's postscript name 460 ImplDevFontAttributes rDFA2; 461 CTFontRef pFont = CTFontCreateWithFontDescriptor( pFD, 0.0, NULL ); 462 CFStringRef pPSName = CTFontCopyPostScriptName( pFont ); 463 const String aPSName = GetOUString( pPSName ); 464 465 rDFA2.mbSymbolFlag = false; 466 rDFA2.mePitch = PITCH_VARIABLE; 467 rDFA2.meWidthType = WIDTH_NORMAL; 468 rDFA2.meWeight = WEIGHT_NORMAL; 469 rDFA2.meItalic = ITALIC_NONE; 470 471 UpdateAttributesFromPSName( aPSName, rDFA2 ); 472 CFRelease( pPSName ); 473 CFRelease( pFont ); 474 475 // show the font details and compare the CTFontDescriptor vs. PSName traits 476 char cMatch = (rDFA.mbSymbolFlag==rDFA2.mbSymbolFlag); 477 cMatch &= (rDFA.meWeight==rDFA2.meWeight); 478 cMatch &= ((rDFA.meItalic==ITALIC_NONE) == (rDFA2.meItalic==ITALIC_NONE)); 479 cMatch &= (rDFA.meWidthType==rDFA2.meWidthType); 480 cMatch = cMatch ? '.' : '#'; 481 482 char aFN[256], aSN[256]; 483 CFStringGetCString( pFamilyName, aFN, sizeof(aFN), kCFStringEncodingUTF8 ); 484 CFStringGetCString( pStyleName, aSN, sizeof(aSN), kCFStringEncodingUTF8 ); 485 486 const ByteString aPSCName( aPSName, RTL_TEXTENCODING_UTF8 ); 487 const char* aPN = aPSCName.GetBuffer(); 488 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", 489 (int)rDFA.mbSymbolFlag,(int)rDFA.meWeight,(int)rDFA.meItalic,(int)rDFA.meWidthType, 490 cMatch, 491 (int)rDFA2.mbSymbolFlag,(int)rDFA2.meWeight,(int)rDFA2.meItalic,(int)rDFA2.meWidthType, 492 bFontEnabled, 493 (int)(nSymbolTrait>>kCTFontClassMaskShift),fWeight,fSlant,fWidth,aFN,aSN,aPN); 494 #endif // (OSL_DEBUG_LEVEL >= 1) 495 496 if( bFontEnabled) 497 { 498 const sal_IntPtr nFontId = (sal_IntPtr)pValue; 499 CTFontData* pFontData = new CTFontData( rDFA, nFontId ); 500 CTFontList* pFontList = (CTFontList*)pContext; 501 pFontList->AddFont( pFontData ); 502 } 503 } 504 505 // ======================================================================= 506 507 CTFontList::CTFontList() 508 : mpCTFontCollection( NULL ) 509 , mpCTFontArray( NULL ) 510 {} 511 512 // ----------------------------------------------------------------------- 513 514 CTFontList::~CTFontList() 515 { 516 CTFontContainer::const_iterator it = maFontContainer.begin(); 517 for(; it != maFontContainer.end(); ++it ) 518 delete (*it).second; 519 maFontContainer.clear(); 520 521 if( mpCTFontArray ) 522 CFRelease( mpCTFontArray ); 523 if( mpCTFontCollection ) 524 CFRelease( mpCTFontCollection ); 525 } 526 527 // ----------------------------------------------------------------------- 528 529 void CTFontList::AddFont( CTFontData* pFontData ) 530 { 531 sal_IntPtr nFontId = pFontData->GetFontId(); 532 maFontContainer[ nFontId ] = pFontData; 533 } 534 535 // ----------------------------------------------------------------------- 536 537 void CTFontList::AnnounceFonts( ImplDevFontList& rFontList ) const 538 { 539 CTFontContainer::const_iterator it = maFontContainer.begin(); 540 for(; it != maFontContainer.end(); ++it ) 541 rFontList.Add( (*it).second->Clone() ); 542 } 543 544 // ----------------------------------------------------------------------- 545 546 ImplMacFontData* CTFontList::GetFontDataFromId( sal_IntPtr nFontId ) const 547 { 548 CTFontContainer::const_iterator it = maFontContainer.find( nFontId ); 549 if( it == maFontContainer.end() ) 550 return NULL; 551 return (*it).second; 552 } 553 554 // ----------------------------------------------------------------------- 555 556 bool CTFontList::Init( void ) 557 { 558 #ifndef DISABLE_CORETEXT_DYNLOAD 559 // check availability of the CoreText API 560 const DynCoreTextSyms& rCT = DynCoreTextSyms::get(); 561 if( !rCT.IsActive() ) 562 return false; 563 #endif // DISABLE_CORETEXT_DYNLOAD 564 565 // enumerate available system fonts 566 static const int nMaxDictEntries = 8; 567 CFMutableDictionaryRef pCFDict = CFDictionaryCreateMutable( NULL, 568 nMaxDictEntries, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); 569 CFDictionaryAddValue( pCFDict, kCTFontCollectionRemoveDuplicatesOption, kCFBooleanTrue ); 570 mpCTFontCollection = rCT.FontCollectionCreateFromAvailableFonts( pCFDict ); 571 CFRelease( pCFDict ); 572 573 mpCTFontArray = rCT.FontCollectionCreateMatchingFontDescriptors( mpCTFontCollection ); 574 const int nFontCount = CFArrayGetCount( mpCTFontArray ); 575 const CFRange aFullRange = CFRangeMake( 0, nFontCount ); 576 CFArrayApplyFunction( mpCTFontArray, aFullRange, CTFontEnumCallBack, this ); 577 578 return true; 579 } 580 581 // ======================================================================= 582 583 #ifndef DISABLE_CORETEXT_DYNLOAD 584 585 DynCoreTextSyms::DynCoreTextSyms( void ) 586 { 587 mbIsActive = false; 588 589 // check if CoreText has been explicitely disabled 590 const char* pEnvStr = getenv( "SAL_DISABLE_CORETEXT"); 591 if( pEnvStr && (pEnvStr[0] != '0') ) 592 return; 593 594 // check CoreText version 595 GetCoreTextVersion = (uint32_t(*)(void))dlsym( RTLD_DEFAULT, "CTGetCoreTextVersion"); 596 if( !GetCoreTextVersion) return; 597 598 const uint32_t nCTVersion = GetCoreTextVersion(); 599 static const uint32_t mykCTVersionNumber10_5 = 0x00020000; 600 if( nCTVersion < mykCTVersionNumber10_5) 601 return; 602 603 // load CoreText symbols dynamically 604 LineGetTrailingWhitespaceWidth = (double(*)(CTLineRef))dlsym( RTLD_DEFAULT, "CTLineGetTrailingWhitespaceWidth"); 605 if( !LineGetTrailingWhitespaceWidth) return; 606 607 LineCreateJustifiedLine = (CTLineRef(*)(CTLineRef,CGFloat,double))dlsym( RTLD_DEFAULT, "CTLineCreateJustifiedLine"); 608 if( !LineCreateJustifiedLine) return; 609 610 LineGetOffsetForStringIndex = (CGFloat(*)(CTLineRef,CFIndex,CGFloat*))dlsym( RTLD_DEFAULT, "CTLineGetOffsetForStringIndex"); 611 if( !LineGetOffsetForStringIndex) return; 612 613 LineGetGlyphRuns = (CFArrayRef(*)(CTLineRef))dlsym( RTLD_DEFAULT, "CTLineGetGlyphRuns"); 614 if( !LineGetGlyphRuns) return; 615 616 RunGetGlyphCount = (CFIndex(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetGlyphCount"); 617 if( !RunGetGlyphCount) return; 618 619 RunGetGlyphsPtr = (const CGGlyph*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetGlyphsPtr"); 620 if( !RunGetGlyphsPtr) return; 621 622 RunGetPositionsPtr = (const CGPoint*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetPositionsPtr"); 623 if( !RunGetPositionsPtr) return; 624 625 RunGetAdvancesPtr = (const CGSize*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetAdvancesPtr"); 626 if( !RunGetAdvancesPtr) return; 627 628 RunGetStringIndicesPtr = (const CFIndex*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetStringIndicesPtr"); 629 if( !RunGetStringIndicesPtr) return; 630 631 FontCollectionCreateFromAvailableFonts = (CTFontCollectionRef(*)(CFDictionaryRef))dlsym( RTLD_DEFAULT, "CTFontCollectionCreateFromAvailableFonts"); 632 if( !FontCollectionCreateFromAvailableFonts) return; 633 634 FontCollectionCreateMatchingFontDescriptors = (CFArrayRef(*)(CTFontCollectionRef))dlsym( RTLD_DEFAULT, "CTFontCollectionCreateMatchingFontDescriptors"); 635 if( !FontCollectionCreateMatchingFontDescriptors) return; 636 637 FontCreatePathForGlyph = (CGPathRef(*)(CTFontRef,CGGlyph,const CGAffineTransform*))dlsym( RTLD_DEFAULT, "CTFontCreatePathForGlyph"); 638 if( !FontCreatePathForGlyph) return; 639 640 FontGetBoundingRectsForGlyphs = (CGRect(*)(CTFontRef,CTFontOrientation,CGGlyph*,CGRect*,CFIndex))dlsym( RTLD_DEFAULT, "CTFontGetBoundingRectsForGlyphs"); 641 if( !FontGetBoundingRectsForGlyphs) return; 642 643 mbIsActive = true; 644 } 645 646 // ----------------------------------------------------------------------- 647 648 const DynCoreTextSyms& DynCoreTextSyms::get( void ) 649 { 650 static DynCoreTextSyms aCT; 651 return aCT; 652 } 653 654 #endif // DISABLE_CORETEXT_DYNLOAD 655 656 // ======================================================================= 657 658 SystemFontList* GetCoretextFontList( void ) 659 { 660 CTFontList* pList = new CTFontList(); 661 if( !pList->Init() ) { 662 delete pList; 663 return NULL; 664 } 665 666 return pList; 667 } 668 669 // ======================================================================= 670 671