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 "atsfonts.hxx" 36 #include "impfont.hxx" 37 38 // ----------------------------------------------------------------------- 39 40 static bool GetDevFontAttributes( ATSUFontID nFontID, ImplDevFontAttributes& rDFA ) 41 { 42 // all ATSU fonts are device fonts that can be directly rotated 43 rDFA.mbOrientation = true; 44 rDFA.mbDevice = true; 45 rDFA.mnQuality = 0; 46 47 // reset the attributes 48 rDFA.meFamily = FAMILY_DONTKNOW; 49 rDFA.mePitch = PITCH_VARIABLE; 50 rDFA.meWidthType = WIDTH_NORMAL; 51 rDFA.meWeight = WEIGHT_NORMAL; 52 rDFA.meItalic = ITALIC_NONE; 53 rDFA.mbSymbolFlag = false; 54 55 // ignore bitmap fonts 56 ATSFontRef rATSFontRef = FMGetATSFontRefFromFont( nFontID ); 57 ByteCount nHeadLen = 0; 58 OSStatus rc = ATSFontGetTable( rATSFontRef, 0x68656164/*head*/, 0, 0, NULL, &nHeadLen ); 59 if( (rc != noErr) || (nHeadLen <= 0) ) 60 return false; 61 62 // all scalable fonts on this platform are subsettable 63 rDFA.mbSubsettable = true; 64 rDFA.mbEmbeddable = false; 65 66 // prepare iterating over all name strings of the font 67 ItemCount nFontNameCount = 0; 68 rc = ATSUCountFontNames( nFontID, &nFontNameCount ); 69 if( rc != noErr ) 70 return false; 71 int nBestNameValue = 0; 72 int nBestStyleValue = 0; 73 FontLanguageCode eBestLangCode = 0; 74 const FontLanguageCode eUILangCode = Application::GetSettings().GetUILanguage(); 75 typedef std::vector<char> NameBuffer; 76 NameBuffer aNameBuffer( 256 ); 77 78 // iterate over all available name strings of the font 79 for( ItemCount nNameIndex = 0; nNameIndex < nFontNameCount; ++nNameIndex ) 80 { 81 ByteCount nNameLength = 0; 82 83 FontNameCode eFontNameCode; 84 FontPlatformCode eFontNamePlatform; 85 FontScriptCode eFontNameScript; 86 FontLanguageCode eFontNameLanguage; 87 rc = ATSUGetIndFontName( nFontID, nNameIndex, 0, NULL, 88 &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage ); 89 if( rc != noErr ) 90 continue; 91 92 // ignore non-interesting name entries 93 if( (eFontNameCode != kFontFamilyName) 94 && (eFontNameCode != kFontStyleName) 95 && (eFontNameCode != kFontPostscriptName) ) 96 continue; 97 98 // heuristic to find the most common font name 99 // prefering default language names or even better the names matching to the UI language 100 int nNameValue = (eFontNameLanguage==eUILangCode) ? 0 : ((eFontNameLanguage==0) ? -10 : -20); 101 rtl_TextEncoding eEncoding = RTL_TEXTENCODING_UNICODE; 102 const int nPlatformEncoding = ((int)eFontNamePlatform << 8) + (int)eFontNameScript; 103 switch( nPlatformEncoding ) 104 { 105 case 0x000: nNameValue += 23; break; // Unicode 1.0 106 case 0x001: nNameValue += 24; break; // Unicode 1.1 107 case 0x002: nNameValue += 25; break; // iso10646_1993 108 case 0x003: nNameValue += 26; break; // UCS-2 109 case 0x301: nNameValue += 27; break; // Win UCS-2 110 case 0x004: // UCS-4 111 case 0x30A: nNameValue += 0; // Win-UCS-4 112 eEncoding = RTL_TEXTENCODING_UCS4; 113 break; 114 case 0x100: nNameValue += 21; // Mac Roman 115 eEncoding = RTL_TEXTENCODING_APPLE_ROMAN; 116 break; 117 case 0x300: nNameValue = 0; // Win Symbol encoded name! 118 rDFA.mbSymbolFlag = true; // (often seen for symbol fonts) 119 break; 120 default: nNameValue = 0; // ignore other encodings 121 break; 122 } 123 124 // ignore name entries with no useful encoding 125 if( nNameValue <= 0 ) 126 continue; 127 if( nNameLength >= aNameBuffer.size() ) 128 continue; 129 130 // get the encoded name 131 aNameBuffer.reserve( nNameLength+1 ); // extra byte helps for debugging 132 rc = ATSUGetIndFontName( nFontID, nNameIndex, nNameLength, &aNameBuffer[0], 133 &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage ); 134 if( rc != noErr ) 135 continue; 136 137 // convert to unicode name 138 UniString aUtf16Name; 139 if( eEncoding == RTL_TEXTENCODING_UNICODE ) // we are just interested in UTF16 encoded names 140 aUtf16Name = UniString( (const sal_Unicode*)&aNameBuffer[0], nNameLength/2 ); 141 else if( eEncoding == RTL_TEXTENCODING_UCS4 ) 142 aUtf16Name = UniString(); // TODO 143 else // assume the non-unicode encoded names are byte encoded 144 aUtf16Name = UniString( &aNameBuffer[0], nNameLength, eEncoding ); 145 146 // ignore empty strings 147 if( aUtf16Name.Len() <= 0 ) 148 continue; 149 150 // handle the name depending on its namecode 151 switch( eFontNameCode ) 152 { 153 case kFontFamilyName: 154 // ignore font names starting with '.' 155 if( aUtf16Name.GetChar(0) == '.' ) 156 nNameValue = 0; 157 else if( rDFA.maName.Len() ) 158 { 159 // even if a family name is not the one we are looking for 160 // it is still useful as a font name alternative 161 if( rDFA.maMapNames.Len() ) 162 rDFA.maMapNames += ';'; 163 rDFA.maMapNames += (nBestNameValue < nNameValue) ? rDFA.maName : aUtf16Name; 164 } 165 if( nBestNameValue < nNameValue ) 166 { 167 // get the best family name 168 nBestNameValue = nNameValue; 169 eBestLangCode = eFontNameLanguage; 170 rDFA.maName = aUtf16Name; 171 } 172 break; 173 case kFontStyleName: 174 // get a style name matching to the family name 175 if( nBestStyleValue < nNameValue ) 176 { 177 nBestStyleValue = nNameValue; 178 rDFA.maStyleName = aUtf16Name; 179 } 180 break; 181 case kFontPostscriptName: 182 // use the postscript name to get some useful info 183 UpdateAttributesFromPSName( aUtf16Name, rDFA ); 184 break; 185 default: 186 // TODO: use other name entries too? 187 break; 188 } 189 } 190 191 #if 0 // multiple-master fonts are mostly obsolete nowadays 192 // if we still want to support them this should probably be done one frame higher 193 ItemCount nMaxInstances = 0; 194 rc = ATSUCountFontInstances ( nFontID, &nMaxInstances ); 195 for( ItemCount nInstanceIndex = 0; nInstanceIndex < nMaxInstances; ++nInstanceIndex ) 196 { 197 ItemCount nMaxVariations = 0; 198 rc = ATSUGetFontInstance( nFontID, nInstanceIndex, 0, NULL, NULL, &nMaxVariations ); 199 if( (rc == noErr) && (nMaxVariations > 0) ) 200 { 201 fprintf(stderr,"\tnMaxVariations=%d\n",(int)nMaxVariations); 202 typedef ::std::vector<ATSUFontVariationAxis> VariationAxisVector; 203 typedef ::std::vector<ATSUFontVariationValue> VariationValueVector; 204 VariationAxisVector aVariationAxes( nMaxVariations ); 205 VariationValueVector aVariationValues( nMaxVariations ); 206 ItemCount nVariationCount = 0; 207 rc = ATSUGetFontInstance ( nFontID, nInstanceIndex, nMaxVariations, 208 &aVariationAxes[0], &aVariationValues[0], &nVariationCount ); 209 fprintf(stderr,"\tnVariationCount=%d\n",(int)nVariationCount); 210 for( ItemCount nVariationIndex = 0; nVariationIndex < nMaxVariations; ++nVariationIndex ) 211 { 212 const char* pTag = (const char*)&aVariationAxes[nVariationIndex]; 213 fprintf(stderr,"\tvariation[%d] \'%c%c%c%c\' is %d\n", (int)nVariationIndex, 214 pTag[3],pTag[2],pTag[1],pTag[0], (int)aVariationValues[nVariationIndex]); 215 } 216 } 217 } 218 #endif 219 220 #if 0 // selecting non-defaulted font features is not enabled yet 221 ByteString aFName( rDFA.maName, RTL_TEXTENCODING_UTF8 ); 222 ByteString aSName( rDFA.maStyleName, RTL_TEXTENCODING_UTF8 ); 223 ItemCount nMaxFeatures = 0; 224 rc = ATSUCountFontFeatureTypes( nFontID, &nMaxFeatures ); 225 fprintf(stderr,"Font \"%s\" \"%s\" has %d features\n",aFName.GetBuffer(),aSName.GetBuffer(),rc); 226 if( (rc == noErr) && (nMaxFeatures > 0) ) 227 { 228 typedef std::vector<ATSUFontFeatureType> FeatureVector; 229 FeatureVector aFeatureVector( nMaxFeatures ); 230 ItemCount nFeatureCount = 0; 231 rc = ATSUGetFontFeatureTypes( nFontID, nMaxFeatures, &aFeatureVector[0], &nFeatureCount ); 232 fprintf(stderr,"nFeatureCount=%d\n",(int)nFeatureCount); 233 for( ItemCount nFeatureIndex = 0; nFeatureIndex < nFeatureCount; ++nFeatureIndex ) 234 { 235 ItemCount nMaxSelectors = 0; 236 rc = ATSUCountFontFeatureSelectors( nFontID, aFeatureVector[nFeatureIndex], &nMaxSelectors ); 237 fprintf(stderr,"\tFeature[%d] = %d has %d selectors\n", 238 (int)nFeatureIndex, (int)aFeatureVector[nFeatureIndex], (int)nMaxSelectors ); 239 typedef std::vector<ATSUFontFeatureSelector> SelectorVector; 240 SelectorVector aSelectorVector( nMaxSelectors ); 241 typedef std::vector<MacOSBoolean> BooleanVector; 242 BooleanVector aEnabledVector( nMaxSelectors ); 243 BooleanVector aExclusiveVector( nMaxSelectors ); 244 ItemCount nSelectorCount = 0; 245 rc = ATSUGetFontFeatureSelectors ( nFontID, aFeatureVector[nFeatureIndex], nMaxSelectors, 246 &aSelectorVector[0], &aEnabledVector[0], &nSelectorCount, &aExclusiveVector[0]); 247 for( ItemCount nSelectorIndex = 0; nSelectorIndex < nSelectorCount; ++nSelectorIndex ) 248 { 249 FontNameCode eFontNameCode; 250 rc = ATSUGetFontFeatureNameCode( nFontID, aFeatureVector[nFeatureIndex], 251 aSelectorVector[nSelectorIndex], &eFontNameCode ); 252 fprintf(stderr,"\t\tselector[%d] n=%d e=%d, x=%d\n", 253 (int)nSelectorIndex, (int)eFontNameCode, 254 aEnabledVector[nSelectorIndex], aExclusiveVector[nSelectorIndex] ); 255 } 256 } 257 } 258 #endif 259 260 bool bRet = (rDFA.maName.Len() > 0); 261 return bRet; 262 } 263 264 // ======================================================================= 265 266 SystemFontList::SystemFontList() 267 { 268 // count available system fonts 269 ItemCount nATSUICompatibleFontsAvailable = 0; 270 if( ATSUFontCount(&nATSUICompatibleFontsAvailable) != noErr ) 271 return; 272 if( nATSUICompatibleFontsAvailable <= 0 ) 273 return; 274 275 // enumerate available system fonts 276 typedef std::vector<ATSUFontID> AtsFontIDVector; 277 AtsFontIDVector aFontIDVector( nATSUICompatibleFontsAvailable ); 278 ItemCount nFontItemsCount = 0; 279 if( ATSUGetFontIDs( &aFontIDVector[0], aFontIDVector.capacity(), &nFontItemsCount ) != noErr ) 280 return; 281 282 BOOST_ASSERT(nATSUICompatibleFontsAvailable == nFontItemsCount && "Strange I would expect them to be equal"); 283 284 // prepare use of the available fonts 285 AtsFontIDVector::const_iterator it = aFontIDVector.begin(); 286 for(; it != aFontIDVector.end(); ++it ) 287 { 288 const ATSUFontID nFontID = *it; 289 ImplDevFontAttributes aDevFontAttr; 290 if( !GetDevFontAttributes( nFontID, aDevFontAttr ) ) 291 continue; 292 ImplMacFontData* pFontData = new ImplMacFontData( aDevFontAttr, nFontID ); 293 maFontContainer[ nFontID ] = pFontData; 294 } 295 296 InitGlyphFallbacks(); 297 } 298 299 // ----------------------------------------------------------------------- 300 301 SystemFontList::~SystemFontList() 302 { 303 MacFontContainer::const_iterator it = maFontContainer.begin(); 304 for(; it != maFontContainer.end(); ++it ) 305 delete (*it).second; 306 maFontContainer.clear(); 307 308 ATSUDisposeFontFallbacks( maFontFallbacks ); 309 } 310 311 // ----------------------------------------------------------------------- 312 313 void SystemFontList::AnnounceFonts( ImplDevFontList& rFontList ) const 314 { 315 MacFontContainer::const_iterator it = maFontContainer.begin(); 316 for(; it != maFontContainer.end(); ++it ) 317 rFontList.Add( (*it).second->Clone() ); 318 } 319 320 // ----------------------------------------------------------------------- 321 322 // not all fonts are suitable for glyph fallback => sort them 323 struct GfbCompare{ bool operator()(const ImplMacFontData*, const ImplMacFontData*); }; 324 325 inline bool GfbCompare::operator()( const ImplMacFontData* pA, const ImplMacFontData* pB ) 326 { 327 // use symbol fonts only as last resort 328 bool bPreferA = !pA->IsSymbolFont(); 329 bool bPreferB = !pB->IsSymbolFont(); 330 if( bPreferA != bPreferB ) 331 return bPreferA; 332 // prefer scalable fonts 333 bPreferA = pA->IsScalable(); 334 bPreferB = pB->IsScalable(); 335 if( bPreferA != bPreferB ) 336 return bPreferA; 337 // prefer non-slanted fonts 338 bPreferA = (pA->GetSlant() == ITALIC_NONE); 339 bPreferB = (pB->GetSlant() == ITALIC_NONE); 340 if( bPreferA != bPreferB ) 341 return bPreferA; 342 // prefer normal weight fonts 343 bPreferA = (pA->GetWeight() == WEIGHT_NORMAL); 344 bPreferB = (pB->GetWeight() == WEIGHT_NORMAL); 345 if( bPreferA != bPreferB ) 346 return bPreferA; 347 // prefer normal width fonts 348 bPreferA = (pA->GetWidthType() == WIDTH_NORMAL); 349 bPreferB = (pB->GetWidthType() == WIDTH_NORMAL); 350 if( bPreferA != bPreferB ) 351 return bPreferA; 352 return false; 353 } 354 355 void SystemFontList::InitGlyphFallbacks() 356 { 357 // sort fonts for "glyph fallback" 358 typedef std::multiset<const ImplMacFontData*,GfbCompare> FallbackSet; 359 FallbackSet aFallbackSet; 360 MacFontContainer::const_iterator it = maFontContainer.begin(); 361 for(; it != maFontContainer.end(); ++it ) 362 { 363 const ImplMacFontData* pIFD = (*it).second; 364 // TODO: subsettable/embeddable glyph fallback only for PDF export? 365 if( pIFD->IsSubsettable() || pIFD->IsEmbeddable() ) 366 aFallbackSet.insert( pIFD ); 367 } 368 369 // tell ATSU about font preferences for "glyph fallback" 370 typedef std::vector<ATSUFontID> AtsFontIDVector; 371 AtsFontIDVector aFallbackVector; 372 aFallbackVector.reserve( maFontContainer.size() ); 373 FallbackSet::const_iterator itFData = aFallbackSet.begin(); 374 for(; itFData != aFallbackSet.end(); ++itFData ) 375 { 376 const ImplMacFontData* pFontData = (*itFData); 377 ATSUFontID nFontID = (ATSUFontID)pFontData->GetFontId(); 378 aFallbackVector.push_back( nFontID ); 379 } 380 381 ATSUCreateFontFallbacks( &maFontFallbacks ); 382 ATSUSetObjFontFallbacks( maFontFallbacks, 383 aFallbackVector.size(), &aFallbackVector[0], kATSUSequentialFallbacksPreferred ); 384 } 385 386 // ----------------------------------------------------------------------- 387 388 ImplMacFontData* SystemFontList::GetFontDataFromId( ATSUFontID nFontId ) const 389 { 390 MacFontContainer::const_iterator it = maFontContainer.find( nFontId ); 391 if( it == maFontContainer.end() ) 392 return NULL; 393 return (*it).second; 394 } 395 396 // ----------------------------------------------------------------------- 397 398