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 <boost/assert.hpp> 26 #include <vector> 27 #include <hash_map> 28 #include <set> 29 30 #include "salgdi.h" 31 #include "atsfonts.hxx" 32 33 #include "vcl/svapp.hxx" 34 #include "vcl/impfont.hxx" 35 36 #include "basegfx/polygon/b2dpolygon.hxx" 37 #include "basegfx/matrix/b2dhommatrix.hxx" 38 39 typedef GlyphID ATSGlyphID; 40 41 // ======================================================================= 42 43 // mac specific physically available font face 44 class AtsFontData 45 : public ImplMacFontData 46 { 47 public: 48 explicit AtsFontData( const ImplDevFontAttributes&, ATSUFontID ); 49 virtual ~AtsFontData( 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 AtsFontList 60 : public SystemFontList 61 { 62 public: 63 explicit AtsFontList( void ); 64 virtual ~AtsFontList( void ); 65 66 virtual void AnnounceFonts( ImplDevFontList& ) const; 67 virtual ImplMacFontData* GetFontDataFromId( sal_IntPtr nFontId ) const; 68 69 private: 70 typedef std::hash_map<sal_IntPtr,AtsFontData*> AtsFontContainer; 71 AtsFontContainer maFontContainer; 72 73 void InitGlyphFallbacks( void ); 74 ATSUFontFallbacks maFontFallbacks; 75 }; 76 77 // ======================================================================= 78 79 AtsFontData::AtsFontData( const ImplDevFontAttributes& rDFA, ATSUFontID nFontId ) 80 : ImplMacFontData( rDFA, (sal_IntPtr)nFontId ) 81 {} 82 83 // ----------------------------------------------------------------------- 84 85 AtsFontData::~AtsFontData( void ) 86 {} 87 88 // ----------------------------------------------------------------------- 89 90 ImplFontData* AtsFontData::Clone( void ) const 91 { 92 AtsFontData* pClone = new AtsFontData(*this); 93 return pClone; 94 } 95 96 // ----------------------------------------------------------------------- 97 98 ImplMacTextStyle* AtsFontData::CreateMacTextStyle( const ImplFontSelectData& rFSD ) const 99 { 100 return new AtsTextStyle( rFSD ); 101 } 102 103 // ----------------------------------------------------------------------- 104 105 ImplFontEntry* AtsFontData::CreateFontInstance( /*const*/ ImplFontSelectData& rFSD ) const 106 { 107 return new ImplFontEntry( rFSD ); 108 } 109 110 // ----------------------------------------------------------------------- 111 112 int AtsFontData::GetFontTable( const char pTagName[5], unsigned char* pResultBuf ) const 113 { 114 DBG_ASSERT( aTagName[4]=='\0', "AtsFontData::GetFontTable with invalid tagname!\n" ); 115 116 const FourCharCode pTagCode = (pTagName[0]<<24) + (pTagName[1]<<16) + (pTagName[2]<<8) + (pTagName[3]<<0); 117 118 // get the byte size of the raw table 119 ATSFontRef rATSFont = FMGetATSFontRefFromFont( (ATSUFontID)mnFontId ); 120 ByteCount nBufSize = 0; 121 OSStatus eStatus = ATSFontGetTable( rATSFont, pTagCode, 0, 0, NULL, &nBufSize ); 122 if( eStatus != noErr ) 123 return 0; 124 125 // get the raw table data if requested 126 if( pResultBuf && (nBufSize > 0)) 127 { 128 ByteCount nRawLength = 0; 129 eStatus = ATSFontGetTable( rATSFont, pTagCode, 0, nBufSize, (void*)pResultBuf, &nRawLength ); 130 if( eStatus != noErr ) 131 return 0; 132 DBG_ASSERT( (nBufSize==nRawLength), "AtsFontData::GetFontTable ByteCount mismatch!\n"); 133 } 134 135 return nBufSize; 136 } 137 138 // ======================================================================= 139 140 AtsTextStyle::AtsTextStyle( const ImplFontSelectData& rFSD ) 141 : ImplMacTextStyle( rFSD ) 142 { 143 // create the style object for ATSUI font attributes 144 ATSUCreateStyle( &maATSUStyle ); 145 const ImplFontSelectData* const pReqFont = &rFSD; 146 147 mpFontData = (AtsFontData*)rFSD.mpFontData; 148 149 // limit the ATS font size to avoid Fixed16.16 overflows 150 double fScaledFontHeight = pReqFont->mfExactHeight; 151 static const float fMaxFontHeight = 144.0; 152 if( fScaledFontHeight > fMaxFontHeight ) 153 { 154 mfFontScale = fScaledFontHeight / fMaxFontHeight; 155 fScaledFontHeight = fMaxFontHeight; 156 } 157 158 // convert font rotation to radian 159 mfFontRotation = pReqFont->mnOrientation * (M_PI / 1800.0); 160 161 // determine if font stretching is needed 162 if( (pReqFont->mnWidth != 0) && (pReqFont->mnWidth != pReqFont->mnHeight) ) 163 { 164 mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight; 165 // set text style to stretching matrix 166 CGAffineTransform aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F ); 167 const ATSUAttributeTag aMatrixTag = kATSUFontMatrixTag; 168 const ATSUAttributeValuePtr aAttr = &aMatrix; 169 const ByteCount aMatrixBytes = sizeof(aMatrix); 170 /*OSStatus eStatus =*/ ATSUSetAttributes( maATSUStyle, 1, &aMatrixTag, &aMatrixBytes, &aAttr ); 171 } 172 } 173 174 // ----------------------------------------------------------------------- 175 176 AtsTextStyle::~AtsTextStyle( void ) 177 { 178 ATSUDisposeStyle( maATSUStyle ); 179 } 180 181 // ----------------------------------------------------------------------- 182 183 void AtsTextStyle::GetFontMetric( float fDPIY, ImplFontMetricData& rMetric ) const 184 { 185 // get the font metrics (in point units) 186 // of the font that has eventually been size-limited 187 188 // get the matching ATSU font handle 189 ATSUFontID fontId; 190 OSStatus err = ::ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(ATSUFontID), &fontId, 0 ); 191 DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font id\n"); 192 193 ATSFontMetrics aMetrics; 194 ATSFontRef rFont = FMGetATSFontRefFromFont( fontId ); 195 err = ATSFontGetHorizontalMetrics ( rFont, kATSOptionFlagsDefault, &aMetrics ); 196 DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font metrics\n"); 197 if( err != noErr ) 198 return; 199 200 // all ATS fonts are scalable fonts 201 rMetric.mbScalableFont = true; 202 // TODO: check if any kerning is possible 203 rMetric.mbKernableFont = true; 204 205 // convert into VCL font metrics (in unscaled pixel units) 206 207 Fixed ptSize; 208 err = ATSUGetAttribute( maATSUStyle, kATSUSizeTag, sizeof(Fixed), &ptSize, 0); 209 DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font size\n"); 210 const double fPointSize = Fix2X( ptSize ); 211 212 // convert quartz units to pixel units 213 // please see the comment in AquaSalGraphics::SetFont() for details 214 const double fPixelSize = (mfFontScale * fDPIY * fPointSize); 215 rMetric.mnAscent = static_cast<long>(+aMetrics.ascent * fPixelSize + 0.5); 216 rMetric.mnDescent = static_cast<long>(-aMetrics.descent * fPixelSize + 0.5); 217 const long nExtDescent = static_cast<long>((-aMetrics.descent + aMetrics.leading) * fPixelSize + 0.5); 218 rMetric.mnExtLeading = nExtDescent - rMetric.mnDescent; 219 rMetric.mnIntLeading = 0; 220 // since ImplFontMetricData::mnWidth is only used for stretching/squeezing fonts 221 // setting this width to the pixel height of the fontsize is good enough 222 // it also makes the calculation of the stretch factor simple 223 rMetric.mnWidth = static_cast<long>(mfFontStretch * fPixelSize + 0.5); 224 } 225 226 // ----------------------------------------------------------------------- 227 228 void AtsTextStyle::SetTextColor( const RGBAColor& rColor ) 229 { 230 RGBColor aAtsColor; 231 aAtsColor.red = (unsigned short)( rColor.GetRed() * 65535.0 ); 232 aAtsColor.green = (unsigned short)( rColor.GetGreen() * 65535.0 ); 233 aAtsColor.blue = (unsigned short)( rColor.GetColor() * 65535.0 ); 234 235 ATSUAttributeTag aTag = kATSUColorTag; 236 ByteCount aValueSize = sizeof( aAtsColor ); 237 ATSUAttributeValuePtr aValue = &aAtsColor; 238 239 /*OSStatus err =*/ ATSUSetAttributes( maATSUStyle, 1, &aTag, &aValueSize, &aValue ); 240 } 241 242 // ----------------------------------------------------------------------- 243 244 bool AtsTextStyle::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect ) const 245 { 246 ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback 247 ATSGlyphID aGlyphId = aGlyphId; 248 ATSGlyphScreenMetrics aGlyphMetrics; 249 const bool bNonAntialiasedText = false; 250 OSStatus eStatus = ATSUGlyphGetScreenMetrics( rATSUStyle, 251 1, &aGlyphId, 0, FALSE, !bNonAntialiasedText, &aGlyphMetrics ); 252 if( eStatus != noErr ) 253 return false; 254 255 const long nMinX = (long)(+aGlyphMetrics.topLeft.x * mfFontScale - 0.5); 256 const long nMaxX = (long)(aGlyphMetrics.width * mfFontScale + 0.5) + nMinX; 257 const long nMinY = (long)(-aGlyphMetrics.topLeft.y * mfFontScale - 0.5); 258 const long nMaxY = (long)(aGlyphMetrics.height * mfFontScale + 0.5) + nMinY; 259 rRect = Rectangle( nMinX, nMinY, nMaxX, nMaxY ); 260 return true; 261 } 262 263 // ----------------------------------------------------------------------- 264 265 // callbacks from ATSUGlyphGetCubicPaths() fore GetGlyphOutline() 266 struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; }; 267 268 static OSStatus GgoLineToProc( const Float32Point* pPoint, void* pData ) 269 { 270 basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon; 271 const basegfx::B2DPoint aB2DPoint( pPoint->x, pPoint->y ); 272 rPolygon.append( aB2DPoint ); 273 return noErr; 274 } 275 276 static OSStatus GgoCurveToProc( const Float32Point* pCP1, const Float32Point* pCP2, 277 const Float32Point* pPoint, void* pData ) 278 { 279 basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon; 280 const sal_uInt32 nPointCount = rPolygon.count(); 281 const basegfx::B2DPoint aB2DControlPoint1( pCP1->x, pCP1->y ); 282 rPolygon.setNextControlPoint( nPointCount-1, aB2DControlPoint1 ); 283 const basegfx::B2DPoint aB2DEndPoint( pPoint->x, pPoint->y ); 284 rPolygon.append( aB2DEndPoint ); 285 const basegfx::B2DPoint aB2DControlPoint2( pCP2->x, pCP2->y ); 286 rPolygon.setPrevControlPoint( nPointCount, aB2DControlPoint2 ); 287 return noErr; 288 } 289 290 static OSStatus GgoClosePathProc( void* pData ) 291 { 292 GgoData* pGgoData = static_cast<GgoData*>(pData); 293 basegfx::B2DPolygon& rPolygon = pGgoData->maPolygon; 294 if( rPolygon.count() > 0 ) 295 pGgoData->mpPolyPoly->append( rPolygon ); 296 rPolygon.clear(); 297 return noErr; 298 } 299 300 static OSStatus GgoMoveToProc( const Float32Point* pPoint, void* pData ) 301 { 302 GgoClosePathProc( pData ); 303 OSStatus eStatus = GgoLineToProc( pPoint, pData ); 304 return eStatus; 305 } 306 307 bool AtsTextStyle::GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& rResult ) const 308 { 309 GgoData aGgoData; 310 aGgoData.mpPolyPoly = &rResult; 311 rResult.clear(); 312 313 OSStatus eGgoStatus = noErr; 314 OSStatus eStatus = ATSUGlyphGetCubicPaths( maATSUStyle, aGlyphId, 315 GgoMoveToProc, GgoLineToProc, GgoCurveToProc, GgoClosePathProc, 316 &aGgoData, &eGgoStatus ); 317 if( (eStatus != noErr) ) // TODO: why is (eGgoStatus!=noErr) when curves are involved? 318 return false; 319 320 GgoClosePathProc( &aGgoData ); 321 322 // apply the font scale 323 if( mfFontScale != 1.0 ) { 324 basegfx::B2DHomMatrix aScale; 325 aScale.scale( +mfFontScale, +mfFontScale ); 326 rResult.transform( aScale ); 327 } 328 329 return true; 330 } 331 332 // ======================================================================= 333 334 static bool GetDevFontAttributes( ATSUFontID nFontID, ImplDevFontAttributes& rDFA ) 335 { 336 // all ATSU fonts are device fonts that can be directly rotated 337 rDFA.mbOrientation = true; 338 rDFA.mbDevice = true; 339 rDFA.mnQuality = 0; 340 341 // reset the attributes 342 rDFA.meFamily = FAMILY_DONTKNOW; 343 rDFA.mePitch = PITCH_VARIABLE; 344 rDFA.meWidthType = WIDTH_NORMAL; 345 rDFA.meWeight = WEIGHT_NORMAL; 346 rDFA.meItalic = ITALIC_NONE; 347 rDFA.mbSymbolFlag = false; 348 349 // ignore bitmap fonts 350 ATSFontRef rATSFontRef = FMGetATSFontRefFromFont( nFontID ); 351 ByteCount nHeadLen = 0; 352 OSStatus rc = ATSFontGetTable( rATSFontRef, 0x68656164/*head*/, 0, 0, NULL, &nHeadLen ); 353 if( (rc != noErr) || (nHeadLen <= 0) ) 354 return false; 355 356 // all scalable fonts on this platform are subsettable 357 rDFA.mbSubsettable = true; 358 rDFA.mbEmbeddable = false; 359 // TODO: these members are needed only for our X11 platform targets 360 rDFA.meAntiAlias = ANTIALIAS_DONTKNOW; 361 rDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW; 362 363 // prepare iterating over all name strings of the font 364 ItemCount nFontNameCount = 0; 365 rc = ATSUCountFontNames( nFontID, &nFontNameCount ); 366 if( rc != noErr ) 367 return false; 368 int nBestNameValue = 0; 369 int nBestStyleValue = 0; 370 FontLanguageCode eBestLangCode = 0; 371 const FontLanguageCode eUILangCode = Application::GetSettings().GetUILanguage(); 372 typedef std::vector<char> NameBuffer; 373 NameBuffer aNameBuffer( 256 ); 374 375 // iterate over all available name strings of the font 376 for( ItemCount nNameIndex = 0; nNameIndex < nFontNameCount; ++nNameIndex ) 377 { 378 ByteCount nNameLength = 0; 379 380 FontNameCode eFontNameCode; 381 FontPlatformCode eFontNamePlatform; 382 FontScriptCode eFontNameScript; 383 FontLanguageCode eFontNameLanguage; 384 rc = ATSUGetIndFontName( nFontID, nNameIndex, 0, NULL, 385 &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage ); 386 if( rc != noErr ) 387 continue; 388 389 // ignore non-interesting name entries 390 if( (eFontNameCode != kFontFamilyName) 391 && (eFontNameCode != kFontStyleName) 392 && (eFontNameCode != kFontPostscriptName) ) 393 continue; 394 395 // heuristic to find the most common font name 396 // prefering default language names or even better the names matching to the UI language 397 int nNameValue = (eFontNameLanguage==eUILangCode) ? 0 : ((eFontNameLanguage==0) ? -10 : -20); 398 rtl_TextEncoding eEncoding = RTL_TEXTENCODING_UNICODE; 399 const int nPlatformEncoding = ((int)eFontNamePlatform << 8) + (int)eFontNameScript; 400 switch( nPlatformEncoding ) 401 { 402 case 0x000: nNameValue += 23; break; // Unicode 1.0 403 case 0x001: nNameValue += 24; break; // Unicode 1.1 404 case 0x002: nNameValue += 25; break; // iso10646_1993 405 case 0x003: nNameValue += 26; break; // UCS-2 406 case 0x301: nNameValue += 27; break; // Win UCS-2 407 case 0x004: // UCS-4 408 case 0x30A: nNameValue += 0; // Win-UCS-4 409 eEncoding = RTL_TEXTENCODING_UCS4; 410 break; 411 case 0x100: nNameValue += 21; // Mac Roman 412 eEncoding = RTL_TEXTENCODING_APPLE_ROMAN; 413 break; 414 case 0x300: nNameValue = 0; // Win Symbol encoded name! 415 rDFA.mbSymbolFlag = true; // (often seen for symbol fonts) 416 break; 417 default: nNameValue = 0; // ignore other encodings 418 break; 419 } 420 421 // ignore name entries with no useful encoding 422 if( nNameValue <= 0 ) 423 continue; 424 if( nNameLength >= aNameBuffer.size() ) 425 continue; 426 427 // get the encoded name 428 aNameBuffer.reserve( nNameLength+1 ); // extra byte helps for debugging 429 rc = ATSUGetIndFontName( nFontID, nNameIndex, nNameLength, &aNameBuffer[0], 430 &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage ); 431 if( rc != noErr ) 432 continue; 433 434 // convert to unicode name 435 UniString aUtf16Name; 436 if( eEncoding == RTL_TEXTENCODING_UNICODE ) // we are just interested in UTF16 encoded names 437 aUtf16Name = UniString( (const sal_Unicode*)&aNameBuffer[0], nNameLength/2 ); 438 else if( eEncoding == RTL_TEXTENCODING_UCS4 ) 439 aUtf16Name = UniString(); // TODO 440 else // assume the non-unicode encoded names are byte encoded 441 aUtf16Name = UniString( &aNameBuffer[0], nNameLength, eEncoding ); 442 443 // ignore empty strings 444 if( aUtf16Name.Len() <= 0 ) 445 continue; 446 447 // handle the name depending on its namecode 448 switch( eFontNameCode ) 449 { 450 case kFontFamilyName: 451 // ignore font names starting with '.' 452 if( aUtf16Name.GetChar(0) == '.' ) 453 nNameValue = 0; 454 else if( rDFA.maName.Len() ) 455 { 456 // even if a family name is not the one we are looking for 457 // it is still useful as a font name alternative 458 if( rDFA.maMapNames.Len() ) 459 rDFA.maMapNames += ';'; 460 rDFA.maMapNames += (nBestNameValue < nNameValue) ? rDFA.maName : aUtf16Name; 461 } 462 if( nBestNameValue < nNameValue ) 463 { 464 // get the best family name 465 nBestNameValue = nNameValue; 466 eBestLangCode = eFontNameLanguage; 467 rDFA.maName = aUtf16Name; 468 } 469 break; 470 case kFontStyleName: 471 // get a style name matching to the family name 472 if( nBestStyleValue < nNameValue ) 473 { 474 nBestStyleValue = nNameValue; 475 rDFA.maStyleName = aUtf16Name; 476 } 477 break; 478 case kFontPostscriptName: 479 // use the postscript name to get some useful info 480 UpdateAttributesFromPSName( aUtf16Name, rDFA ); 481 break; 482 default: 483 // TODO: use other name entries too? 484 break; 485 } 486 } 487 488 bool bRet = (rDFA.maName.Len() > 0); 489 return bRet; 490 } 491 492 // ======================================================================= 493 494 SystemFontList* GetAtsFontList( void ) 495 { 496 return new AtsFontList(); 497 } 498 499 // ======================================================================= 500 501 AtsFontList::AtsFontList() 502 { 503 // count available system fonts 504 ItemCount nATSUICompatibleFontsAvailable = 0; 505 if( ATSUFontCount(&nATSUICompatibleFontsAvailable) != noErr ) 506 return; 507 if( nATSUICompatibleFontsAvailable <= 0 ) 508 return; 509 510 // enumerate available system fonts 511 typedef std::vector<ATSUFontID> AtsFontIDVector; 512 AtsFontIDVector aFontIDVector( nATSUICompatibleFontsAvailable ); 513 ItemCount nFontItemsCount = 0; 514 if( ATSUGetFontIDs( &aFontIDVector[0], aFontIDVector.capacity(), &nFontItemsCount ) != noErr ) 515 return; 516 517 BOOST_ASSERT(nATSUICompatibleFontsAvailable == nFontItemsCount && "Strange I would expect them to be equal"); 518 519 // prepare use of the available fonts 520 AtsFontIDVector::const_iterator it = aFontIDVector.begin(); 521 for(; it != aFontIDVector.end(); ++it ) 522 { 523 const ATSUFontID nFontID = *it; 524 ImplDevFontAttributes aDevFontAttr; 525 if( !GetDevFontAttributes( nFontID, aDevFontAttr ) ) 526 continue; 527 AtsFontData* pFontData = new AtsFontData( aDevFontAttr, nFontID ); 528 maFontContainer[ nFontID ] = pFontData; 529 } 530 531 InitGlyphFallbacks(); 532 } 533 534 // ----------------------------------------------------------------------- 535 536 AtsFontList::~AtsFontList() 537 { 538 AtsFontContainer::const_iterator it = maFontContainer.begin(); 539 for(; it != maFontContainer.end(); ++it ) 540 delete (*it).second; 541 maFontContainer.clear(); 542 543 ATSUDisposeFontFallbacks( maFontFallbacks ); 544 } 545 546 // ----------------------------------------------------------------------- 547 548 void AtsFontList::AnnounceFonts( ImplDevFontList& rFontList ) const 549 { 550 AtsFontContainer::const_iterator it = maFontContainer.begin(); 551 for(; it != maFontContainer.end(); ++it ) 552 rFontList.Add( (*it).second->Clone() ); 553 } 554 555 // ----------------------------------------------------------------------- 556 557 ImplMacFontData* AtsFontList::GetFontDataFromId( sal_IntPtr nFontId ) const 558 { 559 AtsFontContainer::const_iterator it = maFontContainer.find( nFontId ); 560 if( it == maFontContainer.end() ) 561 return NULL; 562 return (*it).second; 563 } 564 565 // ----------------------------------------------------------------------- 566 567 // not all fonts are suitable for glyph fallback => sort them 568 struct GfbCompare{ bool operator()(const ImplMacFontData*, const ImplMacFontData*); }; 569 570 inline bool GfbCompare::operator()( const ImplMacFontData* pA, const ImplMacFontData* pB ) 571 { 572 // use symbol fonts only as last resort 573 bool bPreferA = !pA->IsSymbolFont(); 574 bool bPreferB = !pB->IsSymbolFont(); 575 if( bPreferA != bPreferB ) 576 return bPreferA; 577 // prefer scalable fonts 578 bPreferA = pA->IsScalable(); 579 bPreferB = pB->IsScalable(); 580 if( bPreferA != bPreferB ) 581 return bPreferA; 582 // prefer non-slanted fonts 583 bPreferA = (pA->GetSlant() == ITALIC_NONE); 584 bPreferB = (pB->GetSlant() == ITALIC_NONE); 585 if( bPreferA != bPreferB ) 586 return bPreferA; 587 // prefer normal weight fonts 588 bPreferA = (pA->GetWeight() == WEIGHT_NORMAL); 589 bPreferB = (pB->GetWeight() == WEIGHT_NORMAL); 590 if( bPreferA != bPreferB ) 591 return bPreferA; 592 // prefer normal width fonts 593 bPreferA = (pA->GetWidthType() == WIDTH_NORMAL); 594 bPreferB = (pB->GetWidthType() == WIDTH_NORMAL); 595 if( bPreferA != bPreferB ) 596 return bPreferA; 597 return false; 598 } 599 600 // ----------------------------------------------------------------------- 601 602 void AtsFontList::InitGlyphFallbacks() 603 { 604 // sort fonts for "glyph fallback" 605 typedef std::multiset<const ImplMacFontData*,GfbCompare> FallbackSet; 606 FallbackSet aFallbackSet; 607 AtsFontContainer::const_iterator it = maFontContainer.begin(); 608 for(; it != maFontContainer.end(); ++it ) 609 { 610 const ImplMacFontData* pIFD = (*it).second; 611 // TODO: subsettable/embeddable glyph fallback only for PDF export? 612 if( pIFD->IsSubsettable() || pIFD->IsEmbeddable() ) 613 aFallbackSet.insert( pIFD ); 614 } 615 616 // tell ATSU about font preferences for "glyph fallback" 617 typedef std::vector<ATSUFontID> AtsFontIDVector; 618 AtsFontIDVector aFallbackVector; 619 aFallbackVector.reserve( maFontContainer.size() ); 620 FallbackSet::const_iterator itFData = aFallbackSet.begin(); 621 for(; itFData != aFallbackSet.end(); ++itFData ) 622 { 623 const ImplMacFontData* pFontData = (*itFData); 624 ATSUFontID nFontID = (ATSUFontID)pFontData->GetFontId(); 625 aFallbackVector.push_back( nFontID ); 626 } 627 628 ATSUCreateFontFallbacks( &maFontFallbacks ); 629 ATSUSetObjFontFallbacks( maFontFallbacks, 630 aFallbackVector.size(), &aFallbackVector[0], kATSUSequentialFallbacksPreferred ); 631 } 632 633 // ======================================================================= 634 635