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 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_vcl.hxx" 26 27 #include <boost/assert.hpp> 28 #include <vector> 29 #include <set> 30 31 #include "vcl/svapp.hxx" 32 33 #include "aqua/salgdi.h" 34 #include "aqua/saldata.hxx" 35 #include "aqua/salatsuifontutils.hxx" 36 37 // we have to get the font attributes from the name table 38 // since neither head's macStyle nor OS/2's panose are easily available 39 // during font enumeration. macStyle bits would be not sufficient anyway 40 // and SFNT fonts on Mac usually do not contain an OS/2 table. 41 static void UpdateAttributesFromPSName( const String& rPSName, ImplDevFontAttributes& rDFA ) 42 { 43 ByteString aPSName( rPSName, RTL_TEXTENCODING_UTF8 ); 44 aPSName.ToLowerAscii(); 45 46 // TODO: use a multi-string ignore-case matcher once it becomes available 47 if( (aPSName.Search("regular") != STRING_NOTFOUND) 48 || (aPSName.Search("normal") != STRING_NOTFOUND) 49 || (aPSName.Search("roman") != STRING_NOTFOUND) 50 || (aPSName.Search("medium") != STRING_NOTFOUND) 51 || (aPSName.Search("plain") != STRING_NOTFOUND) 52 || (aPSName.Search("standard") != STRING_NOTFOUND) 53 || (aPSName.Search("std") != STRING_NOTFOUND) ) 54 { 55 rDFA.meWidthType = WIDTH_NORMAL; 56 rDFA.meWeight = WEIGHT_NORMAL; 57 rDFA.meItalic = ITALIC_NONE; 58 } 59 60 // heuristics for font weight 61 if (aPSName.Search("extrablack") != STRING_NOTFOUND) 62 rDFA.meWeight = WEIGHT_BLACK; 63 else if (aPSName.Search("black") != STRING_NOTFOUND) 64 rDFA.meWeight = WEIGHT_BLACK; 65 //else if (aPSName.Search("book") != STRING_NOTFOUND) 66 // rDFA.meWeight = WEIGHT_SEMIBOLD; 67 else if( (aPSName.Search("semibold") != STRING_NOTFOUND) 68 || (aPSName.Search("smbd") != STRING_NOTFOUND)) 69 rDFA.meWeight = WEIGHT_SEMIBOLD; 70 else if (aPSName.Search("ultrabold") != STRING_NOTFOUND) 71 rDFA.meWeight = WEIGHT_ULTRABOLD; 72 else if (aPSName.Search("extrabold") != STRING_NOTFOUND) 73 rDFA.meWeight = WEIGHT_BLACK; 74 else if( (aPSName.Search("bold") != STRING_NOTFOUND) 75 || (aPSName.Search("-bd") != STRING_NOTFOUND)) 76 rDFA.meWeight = WEIGHT_BOLD; 77 else if (aPSName.Search("extralight") != STRING_NOTFOUND) 78 rDFA.meWeight = WEIGHT_ULTRALIGHT; 79 else if (aPSName.Search("ultralight") != STRING_NOTFOUND) 80 rDFA.meWeight = WEIGHT_ULTRALIGHT; 81 else if (aPSName.Search("light") != STRING_NOTFOUND) 82 rDFA.meWeight = WEIGHT_LIGHT; 83 else if (aPSName.Search("thin") != STRING_NOTFOUND) 84 rDFA.meWeight = WEIGHT_THIN; 85 else if (aPSName.Search("-w3") != STRING_NOTFOUND) 86 rDFA.meWeight = WEIGHT_LIGHT; 87 else if (aPSName.Search("-w4") != STRING_NOTFOUND) 88 rDFA.meWeight = WEIGHT_SEMILIGHT; 89 else if (aPSName.Search("-w5") != STRING_NOTFOUND) 90 rDFA.meWeight = WEIGHT_NORMAL; 91 else if (aPSName.Search("-w6") != STRING_NOTFOUND) 92 rDFA.meWeight = WEIGHT_SEMIBOLD; 93 else if (aPSName.Search("-w7") != STRING_NOTFOUND) 94 rDFA.meWeight = WEIGHT_BOLD; 95 else if (aPSName.Search("-w8") != STRING_NOTFOUND) 96 rDFA.meWeight = WEIGHT_ULTRABOLD; 97 else if (aPSName.Search("-w9") != STRING_NOTFOUND) 98 rDFA.meWeight = WEIGHT_BLACK; 99 100 // heuristics for font slant 101 if( (aPSName.Search("italic") != STRING_NOTFOUND) 102 || (aPSName.Search(" ital") != STRING_NOTFOUND) 103 || (aPSName.Search("cursive") != STRING_NOTFOUND) 104 || (aPSName.Search("-it") != STRING_NOTFOUND) 105 || (aPSName.Search("lightit") != STRING_NOTFOUND) 106 || (aPSName.Search("mediumit") != STRING_NOTFOUND) 107 || (aPSName.Search("boldit") != STRING_NOTFOUND) 108 || (aPSName.Search("cnit") != STRING_NOTFOUND) 109 || (aPSName.Search("bdcn") != STRING_NOTFOUND) 110 || (aPSName.Search("bdit") != STRING_NOTFOUND) 111 || (aPSName.Search("condit") != STRING_NOTFOUND) 112 || (aPSName.Search("bookit") != STRING_NOTFOUND) 113 || (aPSName.Search("blackit") != STRING_NOTFOUND) ) 114 rDFA.meItalic = ITALIC_NORMAL; 115 if( (aPSName.Search("oblique") != STRING_NOTFOUND) 116 || (aPSName.Search("inclined") != STRING_NOTFOUND) 117 || (aPSName.Search("slanted") != STRING_NOTFOUND) ) 118 rDFA.meItalic = ITALIC_OBLIQUE; 119 120 // heuristics for font width 121 if( (aPSName.Search("condensed") != STRING_NOTFOUND) 122 || (aPSName.Search("-cond") != STRING_NOTFOUND) 123 || (aPSName.Search("boldcond") != STRING_NOTFOUND) 124 || (aPSName.Search("boldcn") != STRING_NOTFOUND) 125 || (aPSName.Search("cnit") != STRING_NOTFOUND) ) 126 rDFA.meWidthType = WIDTH_CONDENSED; 127 else if (aPSName.Search("narrow") != STRING_NOTFOUND) 128 rDFA.meWidthType = WIDTH_SEMI_CONDENSED; 129 else if (aPSName.Search("expanded") != STRING_NOTFOUND) 130 rDFA.meWidthType = WIDTH_EXPANDED; 131 else if (aPSName.Search("wide") != STRING_NOTFOUND) 132 rDFA.meWidthType = WIDTH_EXPANDED; 133 134 // heuristics for font pitch 135 if( (aPSName.Search("mono") != STRING_NOTFOUND) 136 || (aPSName.Search("courier") != STRING_NOTFOUND) 137 || (aPSName.Search("monaco") != STRING_NOTFOUND) 138 || (aPSName.Search("typewriter") != STRING_NOTFOUND) ) 139 rDFA.mePitch = PITCH_FIXED; 140 141 // heuristics for font family type 142 if( (aPSName.Search("script") != STRING_NOTFOUND) 143 || (aPSName.Search("chancery") != STRING_NOTFOUND) 144 || (aPSName.Search("zapfino") != STRING_NOTFOUND)) 145 rDFA.meFamily = FAMILY_SCRIPT; 146 else if( (aPSName.Search("comic") != STRING_NOTFOUND) 147 || (aPSName.Search("outline") != STRING_NOTFOUND) 148 || (aPSName.Search("pinpoint") != STRING_NOTFOUND) ) 149 rDFA.meFamily = FAMILY_DECORATIVE; 150 else if( (aPSName.Search("sans") != STRING_NOTFOUND) 151 || (aPSName.Search("arial") != STRING_NOTFOUND) ) 152 rDFA.meFamily = FAMILY_SWISS; 153 else if( (aPSName.Search("roman") != STRING_NOTFOUND) 154 || (aPSName.Search("times") != STRING_NOTFOUND) ) 155 rDFA.meFamily = FAMILY_ROMAN; 156 157 // heuristics for codepoint semantic 158 if( (aPSName.Search("symbol") != STRING_NOTFOUND) 159 || (aPSName.Search("dings") != STRING_NOTFOUND) 160 || (aPSName.Search("dingbats") != STRING_NOTFOUND) 161 || (aPSName.Search("ornaments") != STRING_NOTFOUND) 162 || (aPSName.Search("embellishments") != STRING_NOTFOUND) ) 163 rDFA.mbSymbolFlag = true; 164 165 // #i100020# special heuristic for names with single-char styles 166 // NOTE: we are checking name that hasn't been lower-cased 167 if( rPSName.Len() > 3 ) 168 { 169 int i = rPSName.Len(); 170 sal_Unicode c = rPSName.GetChar( --i ); 171 if( c == 'C' ) { // "capitals" 172 rDFA.meFamily = FAMILY_DECORATIVE; 173 c = rPSName.GetChar( --i ); 174 } 175 if( c == 'O' ) { // CFF-based OpenType 176 c = rPSName.GetChar( --i ); 177 } 178 if( c == 'I' ) { // "italic" 179 rDFA.meItalic = ITALIC_NORMAL; 180 c = rPSName.GetChar( --i ); 181 } 182 if( c == 'B' ) // "bold" 183 rDFA.meWeight = WEIGHT_BOLD; 184 if( c == 'C' ) // "capitals" 185 rDFA.meFamily = FAMILY_DECORATIVE; 186 // TODO: check that all single-char styles have been resolved? 187 } 188 } 189 190 // ----------------------------------------------------------------------- 191 192 static bool GetDevFontAttributes( ATSUFontID nFontID, ImplDevFontAttributes& rDFA ) 193 { 194 // all ATSU fonts are device fonts that can be directly rotated 195 rDFA.mbOrientation = true; 196 rDFA.mbDevice = true; 197 rDFA.mnQuality = 0; 198 199 // reset the attributes 200 rDFA.meFamily = FAMILY_DONTKNOW; 201 rDFA.mePitch = PITCH_VARIABLE; 202 rDFA.meWidthType = WIDTH_NORMAL; 203 rDFA.meWeight = WEIGHT_NORMAL; 204 rDFA.meItalic = ITALIC_NONE; 205 rDFA.mbSymbolFlag = false; 206 207 // ignore bitmap fonts 208 ATSFontRef rATSFontRef = FMGetATSFontRefFromFont( nFontID ); 209 ByteCount nHeadLen = 0; 210 OSStatus rc = ATSFontGetTable( rATSFontRef, 0x68656164/*head*/, 0, 0, NULL, &nHeadLen ); 211 if( (rc != noErr) || (nHeadLen <= 0) ) 212 return false; 213 214 // all scalable fonts on this platform are subsettable 215 rDFA.mbSubsettable = true; 216 rDFA.mbEmbeddable = false; 217 218 // prepare iterating over all name strings of the font 219 ItemCount nFontNameCount = 0; 220 rc = ATSUCountFontNames( nFontID, &nFontNameCount ); 221 if( rc != noErr ) 222 return false; 223 int nBestNameValue = 0; 224 int nBestStyleValue = 0; 225 FontLanguageCode eBestLangCode = 0; 226 const FontLanguageCode eUILangCode = Application::GetSettings().GetUILanguage(); 227 typedef std::vector<char> NameBuffer; 228 NameBuffer aNameBuffer( 256 ); 229 230 // iterate over all available name strings of the font 231 for( ItemCount nNameIndex = 0; nNameIndex < nFontNameCount; ++nNameIndex ) 232 { 233 ByteCount nNameLength = 0; 234 235 FontNameCode eFontNameCode; 236 FontPlatformCode eFontNamePlatform; 237 FontScriptCode eFontNameScript; 238 FontLanguageCode eFontNameLanguage; 239 rc = ATSUGetIndFontName( nFontID, nNameIndex, 0, NULL, 240 &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage ); 241 if( rc != noErr ) 242 continue; 243 244 // ignore non-interesting name entries 245 if( (eFontNameCode != kFontFamilyName) 246 && (eFontNameCode != kFontStyleName) 247 && (eFontNameCode != kFontPostscriptName) ) 248 continue; 249 250 // heuristic to find the most common font name 251 // prefering default language names or even better the names matching to the UI language 252 int nNameValue = (eFontNameLanguage==eUILangCode) ? 0 : ((eFontNameLanguage==0) ? -10 : -20); 253 rtl_TextEncoding eEncoding = RTL_TEXTENCODING_UNICODE; 254 const int nPlatformEncoding = ((int)eFontNamePlatform << 8) + (int)eFontNameScript; 255 switch( nPlatformEncoding ) 256 { 257 case 0x000: nNameValue += 23; break; // Unicode 1.0 258 case 0x001: nNameValue += 24; break; // Unicode 1.1 259 case 0x002: nNameValue += 25; break; // iso10646_1993 260 case 0x003: nNameValue += 26; break; // UCS-2 261 case 0x301: nNameValue += 27; break; // Win UCS-2 262 case 0x004: // UCS-4 263 case 0x30A: nNameValue += 0; // Win-UCS-4 264 eEncoding = RTL_TEXTENCODING_UCS4; 265 break; 266 case 0x100: nNameValue += 21; // Mac Roman 267 eEncoding = RTL_TEXTENCODING_APPLE_ROMAN; 268 break; 269 case 0x300: nNameValue = 0; // Win Symbol encoded name! 270 rDFA.mbSymbolFlag = true; // (often seen for symbol fonts) 271 break; 272 default: nNameValue = 0; // ignore other encodings 273 break; 274 } 275 276 // ignore name entries with no useful encoding 277 if( nNameValue <= 0 ) 278 continue; 279 if( nNameLength >= aNameBuffer.size() ) 280 continue; 281 282 // get the encoded name 283 aNameBuffer.reserve( nNameLength+1 ); // extra byte helps for debugging 284 rc = ATSUGetIndFontName( nFontID, nNameIndex, nNameLength, &aNameBuffer[0], 285 &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage ); 286 if( rc != noErr ) 287 continue; 288 289 // convert to unicode name 290 UniString aUtf16Name; 291 if( eEncoding == RTL_TEXTENCODING_UNICODE ) // we are just interested in UTF16 encoded names 292 aUtf16Name = UniString( (const sal_Unicode*)&aNameBuffer[0], nNameLength/2 ); 293 else if( eEncoding == RTL_TEXTENCODING_UCS4 ) 294 aUtf16Name = UniString(); // TODO 295 else // assume the non-unicode encoded names are byte encoded 296 aUtf16Name = UniString( &aNameBuffer[0], nNameLength, eEncoding ); 297 298 // ignore empty strings 299 if( aUtf16Name.Len() <= 0 ) 300 continue; 301 302 // handle the name depending on its namecode 303 switch( eFontNameCode ) 304 { 305 case kFontFamilyName: 306 // ignore font names starting with '.' 307 if( aUtf16Name.GetChar(0) == '.' ) 308 nNameValue = 0; 309 else if( rDFA.maName.Len() ) 310 { 311 // even if a family name is not the one we are looking for 312 // it is still useful as a font name alternative 313 if( rDFA.maMapNames.Len() ) 314 rDFA.maMapNames += ';'; 315 rDFA.maMapNames += (nBestNameValue < nNameValue) ? rDFA.maName : aUtf16Name; 316 } 317 if( nBestNameValue < nNameValue ) 318 { 319 // get the best family name 320 nBestNameValue = nNameValue; 321 eBestLangCode = eFontNameLanguage; 322 rDFA.maName = aUtf16Name; 323 } 324 break; 325 case kFontStyleName: 326 // get a style name matching to the family name 327 if( nBestStyleValue < nNameValue ) 328 { 329 nBestStyleValue = nNameValue; 330 rDFA.maStyleName = aUtf16Name; 331 } 332 break; 333 case kFontPostscriptName: 334 // use the postscript name to get some useful info 335 UpdateAttributesFromPSName( aUtf16Name, rDFA ); 336 break; 337 default: 338 // TODO: use other name entries too? 339 break; 340 } 341 } 342 343 #if 0 // multiple-master fonts are mostly obsolete nowadays 344 // if we still want to support them this should probably be done one frame higher 345 ItemCount nMaxInstances = 0; 346 rc = ATSUCountFontInstances ( nFontID, &nMaxInstances ); 347 for( ItemCount nInstanceIndex = 0; nInstanceIndex < nMaxInstances; ++nInstanceIndex ) 348 { 349 ItemCount nMaxVariations = 0; 350 rc = ATSUGetFontInstance( nFontID, nInstanceIndex, 0, NULL, NULL, &nMaxVariations ); 351 if( (rc == noErr) && (nMaxVariations > 0) ) 352 { 353 fprintf(stderr,"\tnMaxVariations=%d\n",(int)nMaxVariations); 354 typedef ::std::vector<ATSUFontVariationAxis> VariationAxisVector; 355 typedef ::std::vector<ATSUFontVariationValue> VariationValueVector; 356 VariationAxisVector aVariationAxes( nMaxVariations ); 357 VariationValueVector aVariationValues( nMaxVariations ); 358 ItemCount nVariationCount = 0; 359 rc = ATSUGetFontInstance ( nFontID, nInstanceIndex, nMaxVariations, 360 &aVariationAxes[0], &aVariationValues[0], &nVariationCount ); 361 fprintf(stderr,"\tnVariationCount=%d\n",(int)nVariationCount); 362 for( ItemCount nVariationIndex = 0; nVariationIndex < nMaxVariations; ++nVariationIndex ) 363 { 364 const char* pTag = (const char*)&aVariationAxes[nVariationIndex]; 365 fprintf(stderr,"\tvariation[%d] \'%c%c%c%c\' is %d\n", (int)nVariationIndex, 366 pTag[3],pTag[2],pTag[1],pTag[0], (int)aVariationValues[nVariationIndex]); 367 } 368 } 369 } 370 #endif 371 372 #if 0 // selecting non-defaulted font features is not enabled yet 373 ByteString aFName( rDFA.maName, RTL_TEXTENCODING_UTF8 ); 374 ByteString aSName( rDFA.maStyleName, RTL_TEXTENCODING_UTF8 ); 375 ItemCount nMaxFeatures = 0; 376 rc = ATSUCountFontFeatureTypes( nFontID, &nMaxFeatures ); 377 fprintf(stderr,"Font \"%s\" \"%s\" has %d features\n",aFName.GetBuffer(),aSName.GetBuffer(),rc); 378 if( (rc == noErr) && (nMaxFeatures > 0) ) 379 { 380 typedef std::vector<ATSUFontFeatureType> FeatureVector; 381 FeatureVector aFeatureVector( nMaxFeatures ); 382 ItemCount nFeatureCount = 0; 383 rc = ATSUGetFontFeatureTypes( nFontID, nMaxFeatures, &aFeatureVector[0], &nFeatureCount ); 384 fprintf(stderr,"nFeatureCount=%d\n",(int)nFeatureCount); 385 for( ItemCount nFeatureIndex = 0; nFeatureIndex < nFeatureCount; ++nFeatureIndex ) 386 { 387 ItemCount nMaxSelectors = 0; 388 rc = ATSUCountFontFeatureSelectors( nFontID, aFeatureVector[nFeatureIndex], &nMaxSelectors ); 389 fprintf(stderr,"\tFeature[%d] = %d has %d selectors\n", 390 (int)nFeatureIndex, (int)aFeatureVector[nFeatureIndex], (int)nMaxSelectors ); 391 typedef std::vector<ATSUFontFeatureSelector> SelectorVector; 392 SelectorVector aSelectorVector( nMaxSelectors ); 393 typedef std::vector<MacOSBoolean> BooleanVector; 394 BooleanVector aEnabledVector( nMaxSelectors ); 395 BooleanVector aExclusiveVector( nMaxSelectors ); 396 ItemCount nSelectorCount = 0; 397 rc = ATSUGetFontFeatureSelectors ( nFontID, aFeatureVector[nFeatureIndex], nMaxSelectors, 398 &aSelectorVector[0], &aEnabledVector[0], &nSelectorCount, &aExclusiveVector[0]); 399 for( ItemCount nSelectorIndex = 0; nSelectorIndex < nSelectorCount; ++nSelectorIndex ) 400 { 401 FontNameCode eFontNameCode; 402 rc = ATSUGetFontFeatureNameCode( nFontID, aFeatureVector[nFeatureIndex], 403 aSelectorVector[nSelectorIndex], &eFontNameCode ); 404 fprintf(stderr,"\t\tselector[%d] n=%d e=%d, x=%d\n", 405 (int)nSelectorIndex, (int)eFontNameCode, 406 aEnabledVector[nSelectorIndex], aExclusiveVector[nSelectorIndex] ); 407 } 408 } 409 } 410 #endif 411 412 bool bRet = (rDFA.maName.Len() > 0); 413 return bRet; 414 } 415 416 // ======================================================================= 417 418 SystemFontList::SystemFontList() 419 { 420 // count available system fonts 421 ItemCount nATSUICompatibleFontsAvailable = 0; 422 if( ATSUFontCount(&nATSUICompatibleFontsAvailable) != noErr ) 423 return; 424 if( nATSUICompatibleFontsAvailable <= 0 ) 425 return; 426 427 // enumerate available system fonts 428 typedef std::vector<ATSUFontID> AtsFontIDVector; 429 AtsFontIDVector aFontIDVector( nATSUICompatibleFontsAvailable ); 430 ItemCount nFontItemsCount = 0; 431 if( ATSUGetFontIDs( &aFontIDVector[0], aFontIDVector.capacity(), &nFontItemsCount ) != noErr ) 432 return; 433 434 BOOST_ASSERT(nATSUICompatibleFontsAvailable == nFontItemsCount && "Strange I would expect them to be equal"); 435 436 // prepare use of the available fonts 437 AtsFontIDVector::const_iterator it = aFontIDVector.begin(); 438 for(; it != aFontIDVector.end(); ++it ) 439 { 440 const ATSUFontID nFontID = *it; 441 ImplDevFontAttributes aDevFontAttr; 442 if( !GetDevFontAttributes( nFontID, aDevFontAttr ) ) 443 continue; 444 ImplMacFontData* pFontData = new ImplMacFontData( aDevFontAttr, nFontID ); 445 maFontContainer[ nFontID ] = pFontData; 446 } 447 448 InitGlyphFallbacks(); 449 } 450 451 // ----------------------------------------------------------------------- 452 453 SystemFontList::~SystemFontList() 454 { 455 MacFontContainer::const_iterator it = maFontContainer.begin(); 456 for(; it != maFontContainer.end(); ++it ) 457 delete (*it).second; 458 maFontContainer.clear(); 459 460 ATSUDisposeFontFallbacks( maFontFallbacks ); 461 } 462 463 // ----------------------------------------------------------------------- 464 465 void SystemFontList::AnnounceFonts( ImplDevFontList& rFontList ) const 466 { 467 MacFontContainer::const_iterator it = maFontContainer.begin(); 468 for(; it != maFontContainer.end(); ++it ) 469 rFontList.Add( (*it).second->Clone() ); 470 } 471 472 // ----------------------------------------------------------------------- 473 474 // not all fonts are suitable for glyph fallback => sort them 475 struct GfbCompare{ bool operator()(const ImplMacFontData*, const ImplMacFontData*); }; 476 477 inline bool GfbCompare::operator()( const ImplMacFontData* pA, const ImplMacFontData* pB ) 478 { 479 // use symbol fonts only as last resort 480 bool bPreferA = !pA->IsSymbolFont(); 481 bool bPreferB = !pB->IsSymbolFont(); 482 if( bPreferA != bPreferB ) 483 return bPreferA; 484 // prefer scalable fonts 485 bPreferA = pA->IsScalable(); 486 bPreferB = pB->IsScalable(); 487 if( bPreferA != bPreferB ) 488 return bPreferA; 489 // prefer non-slanted fonts 490 bPreferA = (pA->GetSlant() == ITALIC_NONE); 491 bPreferB = (pB->GetSlant() == ITALIC_NONE); 492 if( bPreferA != bPreferB ) 493 return bPreferA; 494 // prefer normal weight fonts 495 bPreferA = (pA->GetWeight() == WEIGHT_NORMAL); 496 bPreferB = (pB->GetWeight() == WEIGHT_NORMAL); 497 if( bPreferA != bPreferB ) 498 return bPreferA; 499 // prefer normal width fonts 500 bPreferA = (pA->GetWidthType() == WIDTH_NORMAL); 501 bPreferB = (pB->GetWidthType() == WIDTH_NORMAL); 502 if( bPreferA != bPreferB ) 503 return bPreferA; 504 return false; 505 } 506 507 void SystemFontList::InitGlyphFallbacks() 508 { 509 // sort fonts for "glyph fallback" 510 typedef std::multiset<const ImplMacFontData*,GfbCompare> FallbackSet; 511 FallbackSet aFallbackSet; 512 MacFontContainer::const_iterator it = maFontContainer.begin(); 513 for(; it != maFontContainer.end(); ++it ) 514 { 515 const ImplMacFontData* pIFD = (*it).second; 516 // TODO: subsettable/embeddable glyph fallback only for PDF export? 517 if( pIFD->IsSubsettable() || pIFD->IsEmbeddable() ) 518 aFallbackSet.insert( pIFD ); 519 } 520 521 // tell ATSU about font preferences for "glyph fallback" 522 typedef std::vector<ATSUFontID> AtsFontIDVector; 523 AtsFontIDVector aFallbackVector; 524 aFallbackVector.reserve( maFontContainer.size() ); 525 FallbackSet::const_iterator itFData = aFallbackSet.begin(); 526 for(; itFData != aFallbackSet.end(); ++itFData ) 527 { 528 const ImplMacFontData* pFontData = (*itFData); 529 ATSUFontID nFontID = (ATSUFontID)pFontData->GetFontId(); 530 aFallbackVector.push_back( nFontID ); 531 } 532 533 ATSUCreateFontFallbacks( &maFontFallbacks ); 534 ATSUSetObjFontFallbacks( maFontFallbacks, 535 aFallbackVector.size(), &aFallbackVector[0], kATSUSequentialFallbacksPreferred ); 536 } 537 538 // ----------------------------------------------------------------------- 539 540 ImplMacFontData* SystemFontList::GetFontDataFromId( ATSUFontID nFontId ) const 541 { 542 MacFontContainer::const_iterator it = maFontContainer.find( nFontId ); 543 if( it == maFontContainer.end() ) 544 return NULL; 545 return (*it).second; 546 } 547 548 // ----------------------------------------------------------------------- 549 550