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 "fontcache.hxx" 28 #include "impfont.hxx" 29 #include "vcl/fontmanager.hxx" 30 31 using namespace psp; 32 33 #ifdef ENABLE_FONTCONFIG 34 #include <fontconfig/fontconfig.h> 35 #include <ft2build.h> 36 #include <fontconfig/fcfreetype.h> 37 // allow compile on baseline (currently with fontconfig 2.2.0) 38 #ifndef FC_WEIGHT_BOOK // TODO: remove when baseline moves to fc>=2.2.1 39 #define FC_WEIGHT_BOOK 75 40 #endif 41 #ifndef FC_EMBEDDED_BITMAP // TODO: remove when baseline moves to fc>=2.3.92 42 #define FC_EMBEDDED_BITMAP "embeddedbitmap" 43 #endif 44 #ifndef FC_FAMILYLANG // TODO: remove when baseline moves to fc>=2.2.97 45 #define FC_FAMILYLANG "familylang" 46 #endif 47 #ifndef FC_HINT_STYLE // TODO: remove when baseline moves to fc>=2.2.91 48 #define FC_HINT_STYLE "hintstyle" 49 #define FC_HINT_NONE 0 50 #define FC_HINT_SLIGHT 1 51 #define FC_HINT_MEDIUM 2 52 #define FC_HINT_FULL 3 53 #endif 54 #else 55 typedef void FcConfig; 56 typedef void FcObjectSet; 57 typedef void FcPattern; 58 typedef void FcFontSet; 59 typedef void FcCharSet; 60 typedef int FcResult; 61 typedef int FcBool; 62 typedef int FcMatchKind; 63 typedef char FcChar8; 64 typedef int FcChar32; 65 typedef unsigned int FT_UInt; 66 typedef void* FT_Face; 67 typedef int FcSetName; 68 #endif 69 70 #include <cstdio> 71 #include <cstdarg> 72 73 #include "unotools/atom.hxx" 74 75 #include "osl/module.h" 76 #include "osl/thread.h" 77 #include "osl/process.h" 78 79 #include "rtl/ustrbuf.hxx" 80 #include "rtl/locale.hxx" 81 82 #include "sal/alloca.h" 83 84 #include <utility> 85 #include <algorithm> 86 87 using namespace osl; 88 using namespace rtl; 89 90 class FontCfgWrapper 91 { 92 oslModule m_pLib; 93 FcFontSet* m_pOutlineSet; 94 95 int m_nFcVersion; 96 FcBool (*m_pFcInit)(); 97 int (*m_pFcGetVersion)(); 98 FcConfig* (*m_pFcConfigGetCurrent)(); 99 FcObjectSet* (*m_pFcObjectSetVaBuild)(const char*,va_list); 100 void (*m_pFcObjectSetDestroy)(FcObjectSet* pSet); 101 FcPattern* (*m_pFcPatternCreate)(); 102 void (*m_pFcPatternDestroy)(FcPattern*); 103 FcFontSet* (*m_pFcFontList)(FcConfig*,FcPattern*,FcObjectSet*); 104 FcFontSet* (*m_pFcConfigGetFonts)(FcConfig*,FcSetName); 105 FcFontSet* (*m_pFcFontSetCreate)(); 106 FcCharSet* (*m_pFcCharSetCreate)(); 107 FcBool (*m_pFcCharSetAddChar)(FcCharSet *, FcChar32); 108 FcBool (*m_pFcCharSetHasChar)(FcCharSet *, FcChar32); 109 void (*m_pFcCharSetDestroy)(FcCharSet*); 110 void (*m_pFcFontSetDestroy)(FcFontSet*); 111 FcBool (*m_pFcFontSetAdd)(FcFontSet*,FcPattern*); 112 void (*m_pFcPatternReference)(FcPattern*); 113 FcResult (*m_pFcPatternGetCharSet)(const FcPattern*,const char*,int,FcCharSet**); 114 FcResult (*m_pFcPatternGetString)(const FcPattern*,const char*,int,FcChar8**); 115 FcResult (*m_pFcPatternGetInteger)(const FcPattern*,const char*,int,int*); 116 FcResult (*m_pFcPatternGetDouble)(const FcPattern*,const char*,int,double*); 117 FcResult (*m_pFcPatternGetBool)(const FcPattern*,const char*,int,FcBool*); 118 void (*m_pFcDefaultSubstitute)(FcPattern *); 119 FcPattern* (*m_pFcFontSetMatch)(FcConfig*,FcFontSet**, int, FcPattern*,FcResult*); 120 FcPattern* (*m_pFcFontMatch)(FcConfig*,FcPattern*,FcResult*); 121 FcBool (*m_pFcConfigAppFontAddFile)(FcConfig*, const FcChar8*); 122 FcBool (*m_pFcConfigAppFontAddDir)(FcConfig*, const FcChar8*); 123 FcBool (*m_pFcConfigParseAndLoad)(FcConfig*,const FcChar8*,FcBool); 124 FcBool (*m_pFcConfigSubstitute)(FcConfig*,FcPattern*,FcMatchKind); 125 126 FcPattern* (*m_pFcPatternDuplicate)(const FcPattern*); 127 FcBool (*m_pFcPatternAddInteger)(FcPattern*,const char*,int); 128 FcBool (*m_pFcPatternAddDouble)(FcPattern*,const char*,double); 129 FcBool (*m_pFcPatternAddBool)(FcPattern*,const char*,FcBool); 130 FcBool (*m_pFcPatternAddCharSet)(FcPattern*,const char*,const FcCharSet*); 131 FcBool (*m_pFcPatternAddString)(FcPattern*,const char*,const FcChar8*); 132 FcBool (*m_pFcPatternDel)(FcPattern*,const char*); 133 134 FT_UInt (*m_pFcFreeTypeCharIndex)(FT_Face,FcChar32); 135 136 oslGenericFunction loadSymbol( const char* ); 137 void addFontSet( FcSetName ); 138 139 FontCfgWrapper(); 140 ~FontCfgWrapper(); 141 142 public: 143 static FontCfgWrapper& get(); 144 static void release(); 145 146 bool isValid() const 147 { return m_pLib != NULL;} 148 149 FcFontSet* getFontSet(); 150 151 FcBool FcInit() 152 { return m_pFcInit(); } 153 154 int FcGetVersion() 155 { return m_pFcGetVersion(); } 156 157 FcConfig* FcConfigGetCurrent() 158 { return m_pFcConfigGetCurrent(); } 159 160 FcObjectSet* FcObjectSetBuild( const char* first, ... ) 161 { 162 va_list ap; 163 va_start( ap, first ); 164 FcObjectSet* pSet = m_pFcObjectSetVaBuild( first, ap ); 165 va_end( ap ); 166 return pSet; 167 } 168 169 void FcObjectSetDestroy( FcObjectSet* pSet ) 170 { m_pFcObjectSetDestroy( pSet ); } 171 172 FcPattern* FcPatternCreate() 173 { return m_pFcPatternCreate(); } 174 175 void FcPatternDestroy( FcPattern* pPattern ) 176 { m_pFcPatternDestroy( pPattern ); } 177 178 FcFontSet* FcFontList( FcConfig* pConfig, FcPattern* pPattern, FcObjectSet* pSet ) 179 { return m_pFcFontList( pConfig, pPattern, pSet ); } 180 181 FcFontSet* FcConfigGetFonts( FcConfig* pConfig, FcSetName eSet) 182 { return m_pFcConfigGetFonts( pConfig, eSet ); } 183 184 FcFontSet* FcFontSetCreate() 185 { return m_pFcFontSetCreate(); } 186 187 FcCharSet* FcCharSetCreate() 188 { return m_pFcCharSetCreate(); } 189 190 FcBool FcCharSetAddChar(FcCharSet *fcs, FcChar32 ucs4) 191 { return m_pFcCharSetAddChar(fcs, ucs4); } 192 193 FcBool FcCharSetHasChar(FcCharSet *fcs, FcChar32 ucs4) 194 { return m_pFcCharSetHasChar(fcs, ucs4); } 195 196 void FcCharSetDestroy( FcCharSet* pSet ) 197 { m_pFcCharSetDestroy( pSet );} 198 199 void FcFontSetDestroy( FcFontSet* pSet ) 200 { m_pFcFontSetDestroy( pSet );} 201 202 FcBool FcFontSetAdd( FcFontSet* pSet, FcPattern* pPattern ) 203 { return m_pFcFontSetAdd( pSet, pPattern ); } 204 205 void FcPatternReference( FcPattern* pPattern ) 206 { m_pFcPatternReference( pPattern ); } 207 208 FcResult FcPatternGetCharSet( const FcPattern* pPattern, const char* object, int n, FcCharSet** s ) 209 { return m_pFcPatternGetCharSet( pPattern, object, n, s ); } 210 211 FcResult FcPatternGetString( const FcPattern* pPattern, const char* object, int n, FcChar8** s ) 212 { return m_pFcPatternGetString( pPattern, object, n, s ); } 213 214 FcResult FcPatternGetInteger( const FcPattern* pPattern, const char* object, int n, int* s ) 215 { return m_pFcPatternGetInteger( pPattern, object, n, s ); } 216 217 FcResult FcPatternGetDouble( const FcPattern* pPattern, const char* object, int n, double* s ) 218 { return m_pFcPatternGetDouble( pPattern, object, n, s ); } 219 220 FcResult FcPatternGetBool( const FcPattern* pPattern, const char* object, int n, FcBool* s ) 221 { return m_pFcPatternGetBool( pPattern, object, n, s ); } 222 FcBool FcConfigAppFontAddFile( FcConfig* pConfig, const FcChar8* pFileName ) 223 { return m_pFcConfigAppFontAddFile( pConfig, pFileName ); } 224 FcBool FcConfigAppFontAddDir(FcConfig* pConfig, const FcChar8* pDirName ) 225 { return m_pFcConfigAppFontAddDir( pConfig, pDirName ); } 226 FcBool FcConfigParseAndLoad( FcConfig* pConfig, const FcChar8* pFileName, FcBool bComplain ) 227 { return m_pFcConfigParseAndLoad( pConfig, pFileName, bComplain ); } 228 229 void FcDefaultSubstitute( FcPattern* pPattern ) 230 { m_pFcDefaultSubstitute( pPattern ); } 231 FcPattern* FcFontSetMatch( FcConfig* pConfig, FcFontSet **ppFontSet, int nset, FcPattern* pPattern, FcResult* pResult ) 232 { return m_pFcFontSetMatch ? m_pFcFontSetMatch( pConfig, ppFontSet, nset, pPattern, pResult ) : 0; } 233 FcPattern* FcFontMatch( FcConfig* pConfig, FcPattern* pPattern, FcResult* pResult ) 234 { return m_pFcFontMatch( pConfig, pPattern, pResult ); } 235 FcBool FcConfigSubstitute( FcConfig* pConfig, FcPattern* pPattern, FcMatchKind eKind ) 236 { return m_pFcConfigSubstitute( pConfig, pPattern, eKind ); } 237 238 FcPattern* FcPatternDuplicate( const FcPattern* pPattern ) const 239 { return m_pFcPatternDuplicate( pPattern ); } 240 FcBool FcPatternAddInteger( FcPattern* pPattern, const char* pObject, int nValue ) 241 { return m_pFcPatternAddInteger( pPattern, pObject, nValue ); } 242 FcBool FcPatternAddDouble( FcPattern* pPattern, const char* pObject, double nValue ) 243 { return m_pFcPatternAddDouble( pPattern, pObject, nValue ); } 244 FcBool FcPatternAddString( FcPattern* pPattern, const char* pObject, const FcChar8* pString ) 245 { return m_pFcPatternAddString( pPattern, pObject, pString ); } 246 FcBool FcPatternAddBool( FcPattern* pPattern, const char* pObject, bool nValue ) 247 { return m_pFcPatternAddBool( pPattern, pObject, nValue ); } 248 FcBool FcPatternAddCharSet(FcPattern* pPattern,const char* pObject,const FcCharSet*pCharSet) 249 { return m_pFcPatternAddCharSet(pPattern,pObject,pCharSet); } 250 FcBool FcPatternDel(FcPattern* pPattern, const char* object) 251 { return m_pFcPatternDel( pPattern, object); } 252 253 FT_UInt FcFreeTypeCharIndex( FT_Face face, FcChar32 ucs4 ) 254 { return m_pFcFreeTypeCharIndex ? m_pFcFreeTypeCharIndex( face, ucs4 ) : 0; } 255 256 public: // TODO: cleanup 257 FcResult FamilyFromPattern(FcPattern* pPattern, FcChar8 **family); 258 std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aFontNameToLocalized; 259 std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aLocalizedToCanonical; 260 }; 261 262 oslGenericFunction FontCfgWrapper::loadSymbol( const char* pSymbol ) 263 { 264 OUString aSym( OUString::createFromAscii( pSymbol ) ); 265 oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData ); 266 #if OSL_DEBUG_LEVEL > 1 267 fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" ); 268 #endif 269 return pSym; 270 } 271 272 FontCfgWrapper::FontCfgWrapper() 273 : m_pLib( NULL ), 274 m_pOutlineSet( NULL ), 275 m_nFcVersion( 0 ) 276 { 277 OUString aLib( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so.1" ) ); 278 m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY ); 279 if( !m_pLib ) 280 { 281 aLib = OUString( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so" ) ); 282 m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY ); 283 } 284 285 if( ! m_pLib ) 286 { 287 #if OSL_DEBUG_LEVEL > 1 288 fprintf( stderr, "no libfontconfig\n" ); 289 #endif 290 return; 291 } 292 293 m_pFcInit = (FcBool(*)()) 294 loadSymbol( "FcInit" ); 295 m_pFcGetVersion = (int(*)()) 296 loadSymbol( "FcGetVersion" ); 297 m_pFcConfigGetCurrent = (FcConfig *(*)()) 298 loadSymbol( "FcConfigGetCurrent" ); 299 m_pFcObjectSetVaBuild = (FcObjectSet*(*)(const char*,va_list)) 300 loadSymbol( "FcObjectSetVaBuild" ); 301 m_pFcObjectSetDestroy = (void(*)(FcObjectSet*)) 302 loadSymbol( "FcObjectSetDestroy" ); 303 m_pFcPatternCreate = (FcPattern*(*)()) 304 loadSymbol( "FcPatternCreate" ); 305 m_pFcPatternDestroy = (void(*)(FcPattern*)) 306 loadSymbol( "FcPatternDestroy" ); 307 m_pFcFontList = (FcFontSet*(*)(FcConfig*,FcPattern*,FcObjectSet*)) 308 loadSymbol( "FcFontList" ); 309 m_pFcConfigGetFonts = (FcFontSet*(*)(FcConfig*,FcSetName)) 310 loadSymbol( "FcConfigGetFonts" ); 311 m_pFcFontSetCreate = (FcFontSet*(*)()) 312 loadSymbol( "FcFontSetCreate" ); 313 m_pFcCharSetCreate = (FcCharSet*(*)()) 314 loadSymbol( "FcCharSetCreate" ); 315 m_pFcCharSetAddChar = (FcBool(*)(FcCharSet*, FcChar32)) 316 loadSymbol( "FcCharSetAddChar" ); 317 m_pFcCharSetHasChar = (FcBool(*)(FcCharSet*, FcChar32)) 318 loadSymbol( "FcCharSetHasChar" ); 319 m_pFcCharSetDestroy = (void(*)(FcCharSet*)) 320 loadSymbol( "FcCharSetDestroy" ); 321 m_pFcFontSetDestroy = (void(*)(FcFontSet*)) 322 loadSymbol( "FcFontSetDestroy" ); 323 m_pFcFontSetAdd = (FcBool(*)(FcFontSet*,FcPattern*)) 324 loadSymbol( "FcFontSetAdd" ); 325 m_pFcPatternReference = (void(*)(FcPattern*)) 326 loadSymbol( "FcPatternReference" ); 327 m_pFcPatternGetCharSet = (FcResult(*)(const FcPattern*,const char*,int,FcCharSet**)) 328 loadSymbol( "FcPatternGetCharSet" ); 329 m_pFcPatternGetString = (FcResult(*)(const FcPattern*,const char*,int,FcChar8**)) 330 loadSymbol( "FcPatternGetString" ); 331 m_pFcPatternGetInteger = (FcResult(*)(const FcPattern*,const char*,int,int*)) 332 loadSymbol( "FcPatternGetInteger" ); 333 m_pFcPatternGetDouble = (FcResult(*)(const FcPattern*,const char*,int,double*)) 334 loadSymbol( "FcPatternGetDouble" ); 335 m_pFcPatternGetBool = (FcResult(*)(const FcPattern*,const char*,int,FcBool*)) 336 loadSymbol( "FcPatternGetBool" ); 337 m_pFcConfigAppFontAddFile = (FcBool(*)(FcConfig*, const FcChar8*)) 338 loadSymbol( "FcConfigAppFontAddFile" ); 339 m_pFcConfigAppFontAddDir = (FcBool(*)(FcConfig*, const FcChar8*)) 340 loadSymbol( "FcConfigAppFontAddDir" ); 341 m_pFcConfigParseAndLoad = (FcBool(*)(FcConfig*, const FcChar8*, FcBool)) 342 loadSymbol( "FcConfigParseAndLoad" ); 343 m_pFcDefaultSubstitute = (void(*)(FcPattern *)) 344 loadSymbol( "FcDefaultSubstitute" ); 345 m_pFcFontSetMatch = (FcPattern*(*)(FcConfig*,FcFontSet**,int,FcPattern*,FcResult*)) 346 loadSymbol( "FcFontSetMatch" ); 347 m_pFcFontMatch = (FcPattern*(*)(FcConfig*,FcPattern*,FcResult*)) 348 loadSymbol( "FcFontMatch" ); 349 m_pFcConfigSubstitute = (FcBool(*)(FcConfig*,FcPattern*,FcMatchKind)) 350 loadSymbol( "FcConfigSubstitute" ); 351 352 m_pFcPatternDuplicate = (FcPattern*(*)(const FcPattern*)) 353 loadSymbol( "FcPatternDuplicate" ); 354 m_pFcPatternAddInteger = (FcBool(*)(FcPattern*,const char*,int)) 355 loadSymbol( "FcPatternAddInteger" ); 356 m_pFcPatternAddDouble = (FcBool(*)(FcPattern*,const char*,double)) 357 loadSymbol( "FcPatternAddDouble" ); 358 m_pFcPatternAddBool = (FcBool(*)(FcPattern*,const char*,FcBool)) 359 loadSymbol( "FcPatternAddBool" ); 360 m_pFcPatternAddCharSet = (FcBool(*)(FcPattern*,const char*,const FcCharSet *)) 361 loadSymbol( "FcPatternAddCharSet" ); 362 m_pFcPatternAddString = (FcBool(*)(FcPattern*,const char*,const FcChar8*)) 363 loadSymbol( "FcPatternAddString" ); 364 m_pFcPatternDel = (FcBool(*)(FcPattern*,const char*)) 365 loadSymbol( "FcPatternDel" ); 366 367 m_pFcFreeTypeCharIndex = (FT_UInt(*)(FT_Face,FcChar32)) 368 loadSymbol( "FcFreeTypeCharIndex" ); 369 370 m_nFcVersion = FcGetVersion(); 371 #if (OSL_DEBUG_LEVEL > 1) 372 fprintf( stderr,"FC_VERSION = %05d\n", m_nFcVersion ); 373 #endif 374 // make minimum version configurable 375 const char* pMinFcVersion = getenv( "SAL_MIN_FC_VERSION"); 376 if( pMinFcVersion ) 377 { 378 const int nMinFcVersion = atoi( pMinFcVersion ); 379 if( m_nFcVersion < nMinFcVersion ) 380 m_pFcInit = NULL; 381 } 382 383 if( ! ( 384 m_pFcInit && 385 m_pFcGetVersion && 386 m_pFcConfigGetCurrent && 387 m_pFcObjectSetVaBuild && 388 m_pFcObjectSetDestroy && 389 m_pFcPatternCreate && 390 m_pFcPatternDestroy && 391 m_pFcFontList && 392 m_pFcConfigGetFonts && 393 m_pFcFontSetCreate && 394 m_pFcCharSetCreate && 395 m_pFcCharSetAddChar && 396 m_pFcCharSetHasChar && 397 m_pFcCharSetDestroy && 398 m_pFcFontSetDestroy && 399 m_pFcFontSetAdd && 400 m_pFcPatternReference && 401 m_pFcPatternGetCharSet && 402 m_pFcPatternGetString && 403 m_pFcPatternGetInteger && 404 m_pFcPatternGetDouble && 405 m_pFcPatternGetBool && 406 m_pFcConfigAppFontAddFile && 407 m_pFcConfigAppFontAddDir && 408 m_pFcConfigParseAndLoad && 409 m_pFcFontMatch && 410 m_pFcDefaultSubstitute && 411 m_pFcConfigSubstitute && 412 m_pFcPatternDuplicate && 413 m_pFcPatternAddInteger && 414 m_pFcPatternAddDouble && 415 m_pFcPatternAddCharSet && 416 m_pFcPatternAddBool && 417 m_pFcPatternAddString && 418 m_pFcPatternDel 419 ) ) 420 { 421 osl_unloadModule( (oslModule)m_pLib ); 422 m_pLib = NULL; 423 #if OSL_DEBUG_LEVEL > 1 424 fprintf( stderr, "not all needed symbols were found in libfontconfig\n" ); 425 #endif 426 return; 427 } 428 429 430 FcInit(); 431 if( ! FcConfigGetCurrent() ) 432 { 433 osl_unloadModule( (oslModule)m_pLib ); 434 m_pLib = NULL; 435 } 436 } 437 438 void FontCfgWrapper::addFontSet( FcSetName eSetName ) 439 { 440 #ifdef ENABLE_FONTCONFIG 441 /* 442 add only acceptable outlined fonts to our config, 443 for future fontconfig use 444 */ 445 FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName ); 446 if( !pOrig ) 447 return; 448 449 // filter the font sets to remove obsolete or duplicate faces 450 for( int i = 0; i < pOrig->nfont; ++i ) 451 { 452 FcPattern* pOrigPattern = pOrig->fonts[i]; 453 // #i115131# ignore non-outline fonts 454 FcBool bOutline = FcFalse; 455 FcResult eOutRes = FcPatternGetBool( pOrigPattern, FC_OUTLINE, 0, &bOutline ); 456 if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) ) 457 continue; 458 // create a pattern to find eventually better alternatives 459 FcPattern* pBetterPattern = pOrigPattern; 460 if( m_nFcVersion > 20400 ) // #i115204# avoid trouble with old FC versions 461 { 462 FcPattern* pTestPattern = FcPatternDuplicate( pOrigPattern ); 463 FcPatternAddBool( pTestPattern, FC_OUTLINE, FcTrue ); 464 // TODO: ignore all attributes that are not interesting for finding dupes 465 // e.g. by using pattern->ImplFontAttr->pattern conversion 466 FcPatternDel( pTestPattern, FC_FONTVERSION ); 467 FcPatternDel( pTestPattern, FC_CHARSET ); 468 FcPatternDel( pTestPattern, FC_FILE ); 469 // find the font face for the dupe-search pattern 470 FcResult eFcResult = FcResultMatch; 471 pBetterPattern = FcFontMatch( FcConfigGetCurrent(), pTestPattern, &eFcResult ); 472 FcPatternDestroy( pTestPattern ); 473 if( eFcResult != FcResultMatch ) 474 continue; 475 // #i115131# double check results and eventually ignore them 476 eOutRes = FcPatternGetBool( pBetterPattern, FC_OUTLINE, 0, &bOutline ); 477 if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) ) 478 continue; 479 } 480 // insert best found pattern for the dupe-search pattern 481 // TODO: skip inserting patterns that are already known in the target fontset 482 FcPatternReference( pBetterPattern ); 483 FcFontSetAdd( m_pOutlineSet, pBetterPattern ); 484 } 485 486 // TODO?: FcFontSetDestroy( pOrig ); 487 #else 488 (void)eSetName; // prevent compiler warning about unused parameter 489 #endif 490 } 491 492 FcFontSet* FontCfgWrapper::getFontSet() 493 { 494 #ifdef ENABLE_FONTCONFIG 495 if( !m_pOutlineSet ) 496 { 497 m_pOutlineSet = FcFontSetCreate(); 498 addFontSet( FcSetSystem ); 499 if( m_nFcVersion > 20400 ) // #i85462# prevent crashes 500 addFontSet( FcSetApplication ); 501 } 502 #endif 503 504 return m_pOutlineSet; 505 } 506 507 FontCfgWrapper::~FontCfgWrapper() 508 { 509 if( m_pOutlineSet ) 510 FcFontSetDestroy( m_pOutlineSet ); 511 if( m_pLib ) 512 osl_unloadModule( (oslModule)m_pLib ); 513 } 514 515 static FontCfgWrapper* pOneInstance = NULL; 516 517 FontCfgWrapper& FontCfgWrapper::get() 518 { 519 if( ! pOneInstance ) 520 pOneInstance = new FontCfgWrapper(); 521 return *pOneInstance; 522 } 523 524 void FontCfgWrapper::release() 525 { 526 if( pOneInstance ) 527 { 528 delete pOneInstance; 529 pOneInstance = NULL; 530 } 531 } 532 533 #ifdef ENABLE_FONTCONFIG 534 namespace 535 { 536 typedef std::pair<FcChar8*, FcChar8*> lang_and_family; 537 538 class localizedsorter 539 { 540 rtl::OLocale maLoc; 541 public: 542 localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {} 543 FcChar8* bestname(const std::vector<lang_and_family> &families); 544 }; 545 546 FcChar8* localizedsorter::bestname(const std::vector<lang_and_family> &families) 547 { 548 FcChar8* candidate = families.begin()->second; 549 rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8)); 550 rtl::OString sFullMatch = sLangMatch; 551 sFullMatch += OString('-'); 552 sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8); 553 554 std::vector<lang_and_family>::const_iterator aEnd = families.end(); 555 bool alreadyclosematch = false; 556 for( std::vector<lang_and_family>::const_iterator aIter = families.begin(); aIter != aEnd; ++aIter ) 557 { 558 const char *pLang = (const char*)aIter->first; 559 if( rtl_str_compare( pLang, sFullMatch.getStr() ) == 0) 560 { 561 // both language and country match 562 candidate = aIter->second; 563 break; 564 } 565 else if( alreadyclosematch ) 566 continue; 567 else if( rtl_str_compare( pLang, sLangMatch.getStr()) == 0) 568 { 569 // just the language matches 570 candidate = aIter->second; 571 alreadyclosematch = true; 572 } 573 else if( rtl_str_compare( pLang, "en") == 0) 574 { 575 // fallback to the english family name 576 candidate = aIter->second; 577 } 578 } 579 return candidate; 580 } 581 } 582 583 FcResult FontCfgWrapper::FamilyFromPattern(FcPattern* pPattern, FcChar8 **family) 584 { 585 FcChar8 *origfamily; 586 FcResult eFamilyRes = FcPatternGetString( pPattern, FC_FAMILY, 0, &origfamily ); 587 *family = origfamily; 588 589 if( eFamilyRes == FcResultMatch) 590 { 591 FcChar8* familylang = NULL; 592 if (FcPatternGetString( pPattern, FC_FAMILYLANG, 0, &familylang ) == FcResultMatch) 593 { 594 std::vector< lang_and_family > lang_and_families; 595 lang_and_families.push_back(lang_and_family(familylang, *family)); 596 int k = 1; 597 while (1) 598 { 599 if (FcPatternGetString( pPattern, FC_FAMILYLANG, k, &familylang ) != FcResultMatch) 600 break; 601 if (FcPatternGetString( pPattern, FC_FAMILY, k, family ) != FcResultMatch) 602 break; 603 lang_and_families.push_back(lang_and_family(familylang, *family)); 604 ++k; 605 } 606 607 //possible to-do, sort by UILocale instead of process locale 608 rtl_Locale* pLoc; 609 osl_getProcessLocale(&pLoc); 610 localizedsorter aSorter(pLoc); 611 *family = aSorter.bestname(lang_and_families); 612 613 std::vector<lang_and_family>::const_iterator aEnd = lang_and_families.end(); 614 for (std::vector<lang_and_family>::const_iterator aIter = lang_and_families.begin(); aIter != aEnd; ++aIter) 615 { 616 const char *candidate = (const char*)(aIter->second); 617 if (rtl_str_compare(candidate, (const char*)(*family)) != 0) 618 m_aFontNameToLocalized[OString(candidate)] = OString((const char*)(*family)); 619 } 620 if (rtl_str_compare((const char*)origfamily, (const char*)(*family)) != 0) 621 m_aLocalizedToCanonical[OString((const char*)(*family))] = OString((const char*)origfamily); 622 } 623 } 624 625 return eFamilyRes; 626 } 627 628 /* 629 * PrintFontManager::initFontconfig 630 */ 631 bool PrintFontManager::initFontconfig() 632 { 633 FontCfgWrapper& rWrapper = FontCfgWrapper::get(); 634 if( ! rWrapper.isValid() ) 635 return false; 636 return true; 637 } 638 639 namespace 640 { 641 weight::type convertWeight(int weight) 642 { 643 // set weight 644 if( weight <= FC_WEIGHT_THIN ) 645 return weight::Thin; 646 else if( weight <= FC_WEIGHT_ULTRALIGHT ) 647 return weight::UltraLight; 648 else if( weight <= FC_WEIGHT_LIGHT ) 649 return weight::Light; 650 else if( weight <= FC_WEIGHT_BOOK ) 651 return weight::SemiLight; 652 else if( weight <= FC_WEIGHT_NORMAL ) 653 return weight::Normal; 654 else if( weight <= FC_WEIGHT_MEDIUM ) 655 return weight::Medium; 656 else if( weight <= FC_WEIGHT_SEMIBOLD ) 657 return weight::SemiBold; 658 else if( weight <= FC_WEIGHT_BOLD ) 659 return weight::Bold; 660 else if( weight <= FC_WEIGHT_ULTRABOLD ) 661 return weight::UltraBold; 662 return weight::Black; 663 } 664 665 italic::type convertSlant(int slant) 666 { 667 // set italic 668 if( slant == FC_SLANT_ITALIC ) 669 return italic::Italic; 670 else if( slant == FC_SLANT_OBLIQUE ) 671 return italic::Oblique; 672 return italic::Upright; 673 } 674 675 pitch::type convertSpacing(int spacing) 676 { 677 // set pitch 678 if( spacing == FC_MONO || spacing == FC_CHARCELL ) 679 return pitch::Fixed; 680 return pitch::Variable; 681 } 682 683 width::type convertWidth(int width) 684 { 685 if (width == FC_WIDTH_ULTRACONDENSED) 686 return width::UltraCondensed; 687 else if (width == FC_WIDTH_EXTRACONDENSED) 688 return width::ExtraCondensed; 689 else if (width == FC_WIDTH_CONDENSED) 690 return width::Condensed; 691 else if (width == FC_WIDTH_SEMICONDENSED) 692 return width::SemiCondensed; 693 else if (width == FC_WIDTH_SEMIEXPANDED) 694 return width::SemiExpanded; 695 else if (width == FC_WIDTH_EXPANDED) 696 return width::Expanded; 697 else if (width == FC_WIDTH_EXTRAEXPANDED) 698 return width::ExtraExpanded; 699 else if (width == FC_WIDTH_ULTRAEXPANDED) 700 return width::UltraExpanded; 701 return width::Normal; 702 } 703 } 704 705 int PrintFontManager::countFontconfigFonts( std::hash_map<rtl::OString, int, rtl::OStringHash>& o_rVisitedPaths ) 706 { 707 int nFonts = 0; 708 709 FontCfgWrapper& rWrapper = FontCfgWrapper::get(); 710 if( !rWrapper.isValid() ) 711 return 0; 712 713 FcFontSet* pFSet = rWrapper.getFontSet(); 714 if( pFSet ) 715 { 716 #if OSL_DEBUG_LEVEL > 1 717 fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont ); 718 #endif 719 for( int i = 0; i < pFSet->nfont; i++ ) 720 { 721 FcChar8* file = NULL; 722 FcChar8* family = NULL; 723 FcChar8* style = NULL; 724 int slant = 0; 725 int weight = 0; 726 int spacing = 0; 727 int nCollectionEntry = -1; 728 FcBool outline = false; 729 730 FcResult eFileRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_FILE, 0, &file ); 731 FcResult eFamilyRes = rWrapper.FamilyFromPattern( pFSet->fonts[i], &family ); 732 FcResult eStyleRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_STYLE, 0, &style ); 733 FcResult eSlantRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SLANT, 0, &slant ); 734 FcResult eWeightRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_WEIGHT, 0, &weight ); 735 FcResult eSpacRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SPACING, 0, &spacing ); 736 FcResult eOutRes = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_OUTLINE, 0, &outline ); 737 FcResult eIndexRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry ); 738 739 if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch ) 740 continue; 741 742 #if (OSL_DEBUG_LEVEL > 2) 743 fprintf( stderr, "found font \"%s\" in file %s\n" 744 " weight = %d, slant = %d, style = \"%s\"\n" 745 " spacing = %d, outline = %d\n" 746 , family, file 747 , eWeightRes == FcResultMatch ? weight : -1 748 , eSpacRes == FcResultMatch ? slant : -1 749 , eStyleRes == FcResultMatch ? (const char*) style : "<nil>" 750 , eSpacRes == FcResultMatch ? spacing : -1 751 , eOutRes == FcResultMatch ? outline : -1 752 ); 753 #endif 754 755 // OSL_ASSERT(eOutRes != FcResultMatch || outline); 756 757 // only outline fonts are usable to psprint anyway 758 if( eOutRes == FcResultMatch && ! outline ) 759 continue; 760 761 // see if this font is already cached 762 // update attributes 763 std::list< PrintFont* > aFonts; 764 OString aDir, aBase, aOrgPath( (sal_Char*)file ); 765 splitPath( aOrgPath, aDir, aBase ); 766 767 o_rVisitedPaths[aDir] = 1; 768 769 int nDirID = getDirectoryAtom( aDir, true ); 770 if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) ) 771 { 772 #if OSL_DEBUG_LEVEL > 2 773 fprintf( stderr, "file %s not cached\n", aBase.getStr() ); 774 #endif 775 // not known, analyze font file to get attributes 776 // not described by fontconfig (e.g. alias names, PSName) 777 std::list< OString > aDummy; 778 analyzeFontFile( nDirID, aBase, aDummy, aFonts ); 779 #if OSL_DEBUG_LEVEL > 1 780 if( aFonts.empty() ) 781 fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() ); 782 #endif 783 } 784 if( aFonts.empty() ) 785 { 786 // TODO: remove fonts unusable to psprint from fontset 787 continue; 788 } 789 790 int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( (sal_Char*)family ), RTL_TEXTENCODING_UTF8 ), sal_True ); 791 PrintFont* pUpdate = aFonts.front(); 792 std::list<PrintFont*>::const_iterator second_font = aFonts.begin(); 793 ++second_font; 794 if( second_font != aFonts.end() ) // more than one font 795 { 796 // a collection entry, get the correct index 797 if( eIndexRes == FcResultMatch && nCollectionEntry != -1 ) 798 { 799 for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it ) 800 { 801 if( (*it)->m_eType == fonttype::TrueType && 802 static_cast<TrueTypeFontFile*>(*it)->m_nCollectionEntry == nCollectionEntry ) 803 { 804 pUpdate = *it; 805 break; 806 } 807 } 808 // update collection entry 809 // additional entries will be created in the cache 810 // if this is a new index (that is if the loop above 811 // ran to the end of the list) 812 if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here 813 static_cast<TrueTypeFontFile*>(pUpdate)->m_nCollectionEntry = nCollectionEntry; 814 } 815 else 816 { 817 #if OSL_DEBUG_LEVEL > 1 818 fprintf( stderr, "multiple fonts for file, but no index in fontconfig pattern ! (index res = %d collection entry = %d\nfile will not be used\n", eIndexRes, nCollectionEntry ); 819 #endif 820 // we have found more than one font in this file 821 // but fontconfig will not tell us which index is meant 822 // -> something is in disorder, do not use this font 823 pUpdate = NULL; 824 } 825 } 826 827 if( pUpdate ) 828 { 829 // set family name 830 if( pUpdate->m_nFamilyName != nFamilyName ) 831 { 832 #if 0 // fontconfig prefers nameid=16 for the family name which is all fine 833 // but Writer suffers from #i79878# 834 // the only reasonable workaround for now is to use the classic nameid=1 835 pUpdate->m_aAliases.remove( pUpdate->m_nFamilyName ); 836 pUpdate->m_aAliases.push_back( pUpdate->m_nFamilyName ); 837 pUpdate->m_aAliases.remove( nFamilyName ); 838 pUpdate->m_nFamilyName = nFamilyName; 839 #endif 840 } 841 if( eWeightRes == FcResultMatch ) 842 pUpdate->m_eWeight = convertWeight(weight); 843 if( eSpacRes == FcResultMatch ) 844 pUpdate->m_ePitch = convertSpacing(spacing); 845 if( eSlantRes == FcResultMatch ) 846 pUpdate->m_eItalic = convertSlant(slant); 847 if( eStyleRes == FcResultMatch ) 848 { 849 pUpdate->m_aStyleName = OStringToOUString( OString( (sal_Char*)style ), RTL_TEXTENCODING_UTF8 ); 850 } 851 852 // update font cache 853 m_pFontCache->updateFontCacheEntry( pUpdate, false ); 854 // sort into known fonts 855 fontID aFont = m_nNextFontID++; 856 m_aFonts[ aFont ] = pUpdate; 857 m_aFontFileToFontID[ aBase ].insert( aFont ); 858 nFonts++; 859 #if OSL_DEBUG_LEVEL > 2 860 fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont ); 861 #endif 862 } 863 // clean up the fonts we did not put into the list 864 for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it ) 865 { 866 if( *it != pUpdate ) 867 { 868 m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item 869 delete *it; 870 } 871 } 872 } 873 } 874 875 // how does one get rid of the config ? 876 #if OSL_DEBUG_LEVEL > 1 877 fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts ); 878 #endif 879 return nFonts; 880 } 881 882 void PrintFontManager::deinitFontconfig() 883 { 884 FontCfgWrapper::release(); 885 } 886 887 int PrintFontManager::FreeTypeCharIndex( void *pFace, sal_uInt32 aChar ) 888 { 889 FontCfgWrapper& rWrapper = FontCfgWrapper::get(); 890 return rWrapper.isValid() ? rWrapper.FcFreeTypeCharIndex( (FT_Face)pFace, aChar ) : 0; 891 } 892 893 bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName ) 894 { 895 FontCfgWrapper& rWrapper = FontCfgWrapper::get(); 896 if( ! rWrapper.isValid() ) 897 return false; 898 899 // workaround for a stability problems in older FC versions 900 // when handling application specifc fonts 901 const int nVersion = rWrapper.FcGetVersion(); 902 if( nVersion <= 20400 ) 903 return false; 904 const char* pDirName = (const char*)rDirName.getStr(); 905 bool bDirOk = (rWrapper.FcConfigAppFontAddDir( rWrapper.FcConfigGetCurrent(), (FcChar8*)pDirName ) == FcTrue); 906 907 #if OSL_DEBUG_LEVEL > 1 908 fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bDirOk ); 909 #endif 910 911 if( !bDirOk ) 912 return false; 913 914 // load dir-specific fc-config file too if available 915 const rtl::OString aConfFileName = rDirName + "/fc_local.conf"; 916 FILE* pCfgFile = fopen( aConfFileName.getStr(), "rb" ); 917 if( pCfgFile ) 918 { 919 fclose( pCfgFile); 920 bool bCfgOk = rWrapper.FcConfigParseAndLoad( rWrapper.FcConfigGetCurrent(), 921 (FcChar8*)aConfFileName.getStr(), FcTrue ); 922 if( !bCfgOk ) 923 fprintf( stderr, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName.getStr(), bCfgOk ); 924 } 925 926 return true; 927 } 928 929 static void addtopattern(FontCfgWrapper& rWrapper, FcPattern *pPattern, 930 italic::type eItalic, weight::type eWeight, width::type eWidth, pitch::type ePitch) 931 { 932 if( eItalic != italic::Unknown ) 933 { 934 int nSlant = FC_SLANT_ROMAN; 935 switch( eItalic ) 936 { 937 case italic::Italic: nSlant = FC_SLANT_ITALIC;break; 938 case italic::Oblique: nSlant = FC_SLANT_OBLIQUE;break; 939 default: 940 break; 941 } 942 rWrapper.FcPatternAddInteger( pPattern, FC_SLANT, nSlant ); 943 } 944 if( eWeight != weight::Unknown ) 945 { 946 int nWeight = FC_WEIGHT_NORMAL; 947 switch( eWeight ) 948 { 949 case weight::Thin: nWeight = FC_WEIGHT_THIN;break; 950 case weight::UltraLight: nWeight = FC_WEIGHT_ULTRALIGHT;break; 951 case weight::Light: nWeight = FC_WEIGHT_LIGHT;break; 952 case weight::SemiLight: nWeight = FC_WEIGHT_BOOK;break; 953 case weight::Normal: nWeight = FC_WEIGHT_NORMAL;break; 954 case weight::Medium: nWeight = FC_WEIGHT_MEDIUM;break; 955 case weight::SemiBold: nWeight = FC_WEIGHT_SEMIBOLD;break; 956 case weight::Bold: nWeight = FC_WEIGHT_BOLD;break; 957 case weight::UltraBold: nWeight = FC_WEIGHT_ULTRABOLD;break; 958 case weight::Black: nWeight = FC_WEIGHT_BLACK;break; 959 default: 960 break; 961 } 962 rWrapper.FcPatternAddInteger( pPattern, FC_WEIGHT, nWeight ); 963 } 964 if( eWidth != width::Unknown ) 965 { 966 int nWidth = FC_WIDTH_NORMAL; 967 switch( eWidth ) 968 { 969 case width::UltraCondensed: nWidth = FC_WIDTH_ULTRACONDENSED;break; 970 case width::ExtraCondensed: nWidth = FC_WIDTH_EXTRACONDENSED;break; 971 case width::Condensed: nWidth = FC_WIDTH_CONDENSED;break; 972 case width::SemiCondensed: nWidth = FC_WIDTH_SEMICONDENSED;break; 973 case width::Normal: nWidth = FC_WIDTH_NORMAL;break; 974 case width::SemiExpanded: nWidth = FC_WIDTH_SEMIEXPANDED;break; 975 case width::Expanded: nWidth = FC_WIDTH_EXPANDED;break; 976 case width::ExtraExpanded: nWidth = FC_WIDTH_EXTRAEXPANDED;break; 977 case width::UltraExpanded: nWidth = FC_WIDTH_ULTRACONDENSED;break; 978 default: 979 break; 980 } 981 rWrapper.FcPatternAddInteger( pPattern, FC_WIDTH, nWidth ); 982 } 983 if( ePitch != pitch::Unknown ) 984 { 985 int nSpacing = FC_PROPORTIONAL; 986 switch( ePitch ) 987 { 988 case pitch::Fixed: nSpacing = FC_MONO;break; 989 case pitch::Variable: nSpacing = FC_PROPORTIONAL;break; 990 default: 991 break; 992 } 993 rWrapper.FcPatternAddInteger( pPattern, FC_SPACING, nSpacing ); 994 if (nSpacing == FC_MONO) 995 rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)"monospace"); 996 } 997 } 998 999 rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName, 1000 rtl::OUString& rMissingCodes, const rtl::OString &rLangAttrib, 1001 italic::type &rItalic, weight::type &rWeight, 1002 width::type &rWidth, pitch::type &rPitch) const 1003 { 1004 rtl::OUString aName; 1005 FontCfgWrapper& rWrapper = FontCfgWrapper::get(); 1006 if( ! rWrapper.isValid() ) 1007 return aName; 1008 1009 // build pattern argument for fontconfig query 1010 FcPattern* pPattern = rWrapper.FcPatternCreate(); 1011 1012 // Prefer scalable fonts 1013 rWrapper.FcPatternAddBool( pPattern, FC_SCALABLE, FcTrue ); 1014 1015 const rtl::OString aTargetName = rtl::OUStringToOString( rFontName, RTL_TEXTENCODING_UTF8 ); 1016 const FcChar8* pTargetNameUtf8 = (FcChar8*)aTargetName.getStr(); 1017 rWrapper.FcPatternAddString( pPattern, FC_FAMILY, pTargetNameUtf8 ); 1018 1019 const FcChar8* pLangAttribUtf8 = (FcChar8*)rLangAttrib.getStr(); 1020 if( rLangAttrib.getLength() ) 1021 rWrapper.FcPatternAddString( pPattern, FC_LANG, pLangAttribUtf8 ); 1022 1023 // Add required Unicode characters, if any 1024 if ( rMissingCodes.getLength() ) 1025 { 1026 FcCharSet *unicodes = rWrapper.FcCharSetCreate(); 1027 for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); ) 1028 { 1029 // also handle unicode surrogates 1030 const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex ); 1031 rWrapper.FcCharSetAddChar( unicodes, nCode ); 1032 } 1033 rWrapper.FcPatternAddCharSet( pPattern, FC_CHARSET, unicodes); 1034 rWrapper.FcCharSetDestroy( unicodes ); 1035 } 1036 1037 addtopattern(rWrapper, pPattern, rItalic, rWeight, rWidth, rPitch); 1038 1039 // query fontconfig for a substitute 1040 rWrapper.FcConfigSubstitute( rWrapper.FcConfigGetCurrent(), pPattern, FcMatchPattern ); 1041 rWrapper.FcDefaultSubstitute( pPattern ); 1042 1043 // process the result of the fontconfig query 1044 FcResult eResult = FcResultNoMatch; 1045 FcFontSet* pFontSet = rWrapper.getFontSet(); 1046 FcPattern* pResult = rWrapper.FcFontSetMatch( rWrapper.FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult ); 1047 rWrapper.FcPatternDestroy( pPattern ); 1048 1049 FcFontSet* pSet = NULL; 1050 if( pResult ) 1051 { 1052 pSet = rWrapper.FcFontSetCreate(); 1053 // info: destroying the pSet destroys pResult implicitly 1054 // since pResult was "added" to pSet 1055 rWrapper.FcFontSetAdd( pSet, pResult ); 1056 } 1057 1058 if( pSet ) 1059 { 1060 if( pSet->nfont > 0 ) 1061 { 1062 //extract the closest match 1063 FcChar8* family = NULL; 1064 FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family ); 1065 1066 // get the family name 1067 if( eFileRes == FcResultMatch ) 1068 { 1069 OString sFamily((sal_Char*)family); 1070 std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aFontNameToLocalized.find(sFamily); 1071 if (aI != rWrapper.m_aFontNameToLocalized.end()) 1072 sFamily = aI->second; 1073 aName = rtl::OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 ); 1074 1075 1076 int val = 0; 1077 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WEIGHT, 0, &val)) 1078 rWeight = convertWeight(val); 1079 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SLANT, 0, &val)) 1080 rItalic = convertSlant(val); 1081 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SPACING, 0, &val)) 1082 rPitch = convertSpacing(val); 1083 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WIDTH, 0, &val)) 1084 rWidth = convertWidth(val); 1085 } 1086 1087 // update rMissingCodes by removing resolved unicodes 1088 if( rMissingCodes.getLength() > 0 ) 1089 { 1090 sal_uInt32* pRemainingCodes = (sal_uInt32*)alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) ); 1091 int nRemainingLen = 0; 1092 FcCharSet* unicodes; 1093 if( !rWrapper.FcPatternGetCharSet( pSet->fonts[0], FC_CHARSET, 0, &unicodes ) ) 1094 { 1095 for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); ) 1096 { 1097 // also handle unicode surrogates 1098 const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex ); 1099 if( rWrapper.FcCharSetHasChar( unicodes, nCode ) != FcTrue ) 1100 pRemainingCodes[ nRemainingLen++ ] = nCode; 1101 } 1102 } 1103 rMissingCodes = OUString( pRemainingCodes, nRemainingLen ); 1104 } 1105 } 1106 1107 rWrapper.FcFontSetDestroy( pSet ); 1108 } 1109 1110 return aName; 1111 } 1112 1113 bool PrintFontManager::getFontOptions( 1114 const FastPrintFontInfo& rInfo, int nSize, void (*subcallback)(void*), 1115 ImplFontOptions& rOptions) const 1116 { 1117 #ifndef ENABLE_FONTCONFIG 1118 (void)rInfo;(void)nSize;(void)subcallback;(void)rOptions; 1119 return false; 1120 #else // ENABLE_FONTCONFIG 1121 FontCfgWrapper& rWrapper = FontCfgWrapper::get(); 1122 if( ! rWrapper.isValid() ) 1123 return false; 1124 1125 FcConfig* pConfig = rWrapper.FcConfigGetCurrent(); 1126 FcPattern* pPattern = rWrapper.FcPatternCreate(); 1127 1128 OString sFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 ); 1129 1130 std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aLocalizedToCanonical.find(sFamily); 1131 if (aI != rWrapper.m_aLocalizedToCanonical.end()) 1132 sFamily = aI->second; 1133 if( sFamily.getLength() ) 1134 rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)sFamily.getStr() ); 1135 1136 addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch); 1137 rWrapper.FcPatternAddDouble( pPattern, FC_PIXEL_SIZE, nSize); 1138 1139 FcBool embitmap = true, antialias = true, autohint = true, hinting = true; 1140 int hintstyle = FC_HINT_FULL; 1141 1142 rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern ); 1143 if (subcallback) subcallback(pPattern); 1144 rWrapper.FcDefaultSubstitute( pPattern ); 1145 1146 FcResult eResult = FcResultNoMatch; 1147 FcFontSet* pFontSet = rWrapper.getFontSet(); 1148 FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult ); 1149 if( pResult ) 1150 { 1151 FcFontSet* pSet = rWrapper.FcFontSetCreate(); 1152 rWrapper.FcFontSetAdd( pSet, pResult ); 1153 if( pSet->nfont > 0 ) 1154 { 1155 FcResult eEmbeddedBitmap = rWrapper.FcPatternGetBool(pSet->fonts[0], 1156 FC_EMBEDDED_BITMAP, 0, &embitmap); 1157 FcResult eAntialias = rWrapper.FcPatternGetBool(pSet->fonts[0], 1158 FC_ANTIALIAS, 0, &antialias); 1159 FcResult eAutoHint = rWrapper.FcPatternGetBool(pSet->fonts[0], 1160 FC_AUTOHINT, 0, &autohint); 1161 FcResult eHinting = rWrapper.FcPatternGetBool(pSet->fonts[0], 1162 FC_HINTING, 0, &hinting); 1163 /*FcResult eHintStyle =*/ rWrapper.FcPatternGetInteger( pSet->fonts[0], 1164 FC_HINT_STYLE, 0, &hintstyle); 1165 1166 if( eEmbeddedBitmap == FcResultMatch ) 1167 rOptions.meEmbeddedBitmap = embitmap ? EMBEDDEDBITMAP_TRUE : EMBEDDEDBITMAP_FALSE; 1168 if( eAntialias == FcResultMatch ) 1169 rOptions.meAntiAlias = antialias ? ANTIALIAS_TRUE : ANTIALIAS_FALSE; 1170 if( eAutoHint == FcResultMatch ) 1171 rOptions.meAutoHint = autohint ? AUTOHINT_TRUE : AUTOHINT_FALSE; 1172 if( eHinting == FcResultMatch ) 1173 rOptions.meHinting = hinting ? HINTING_TRUE : HINTING_FALSE; 1174 switch (hintstyle) 1175 { 1176 case FC_HINT_NONE: rOptions.meHintStyle = HINT_NONE; break; 1177 case FC_HINT_SLIGHT: rOptions.meHintStyle = HINT_SLIGHT; break; 1178 case FC_HINT_MEDIUM: rOptions.meHintStyle = HINT_MEDIUM; break; 1179 default: // fall through 1180 case FC_HINT_FULL: rOptions.meHintStyle = HINT_FULL; break; 1181 } 1182 } 1183 // info: destroying the pSet destroys pResult implicitly 1184 // since pResult was "added" to pSet 1185 rWrapper.FcFontSetDestroy( pSet ); 1186 } 1187 1188 // cleanup 1189 rWrapper.FcPatternDestroy( pPattern ); 1190 1191 // TODO: return true only if non-default font options are set 1192 const bool bOK = (pResult != NULL); 1193 return bOK; 1194 #endif 1195 } 1196 1197 bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale ) 1198 { 1199 FontCfgWrapper& rWrapper = FontCfgWrapper::get(); 1200 if( ! rWrapper.isValid() ) 1201 return false; 1202 1203 FcConfig* pConfig = rWrapper.FcConfigGetCurrent(); 1204 FcPattern* pPattern = rWrapper.FcPatternCreate(); 1205 1206 OString aLangAttrib; 1207 // populate pattern with font characteristics 1208 if( rLocale.Language.getLength() ) 1209 { 1210 OUStringBuffer aLang(6); 1211 aLang.append( rLocale.Language ); 1212 if( rLocale.Country.getLength() ) 1213 { 1214 aLang.append( sal_Unicode('-') ); 1215 aLang.append( rLocale.Country ); 1216 } 1217 aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ); 1218 } 1219 if( aLangAttrib.getLength() ) 1220 rWrapper.FcPatternAddString( pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr() ); 1221 1222 OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 ); 1223 if( aFamily.getLength() ) 1224 rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr() ); 1225 1226 addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch); 1227 1228 rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern ); 1229 rWrapper.FcDefaultSubstitute( pPattern ); 1230 FcResult eResult = FcResultNoMatch; 1231 FcFontSet *pFontSet = rWrapper.getFontSet(); 1232 FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult ); 1233 bool bSuccess = false; 1234 if( pResult ) 1235 { 1236 FcFontSet* pSet = rWrapper.FcFontSetCreate(); 1237 rWrapper.FcFontSetAdd( pSet, pResult ); 1238 if( pSet->nfont > 0 ) 1239 { 1240 //extract the closest match 1241 FcChar8* file = NULL; 1242 FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FILE, 0, &file ); 1243 if( eFileRes == FcResultMatch ) 1244 { 1245 OString aDir, aBase, aOrgPath( (sal_Char*)file ); 1246 splitPath( aOrgPath, aDir, aBase ); 1247 int nDirID = getDirectoryAtom( aDir, true ); 1248 fontID aFont = findFontFileID( nDirID, aBase ); 1249 if( aFont > 0 ) 1250 bSuccess = getFontFastInfo( aFont, rInfo ); 1251 } 1252 } 1253 // info: destroying the pSet destroys pResult implicitly 1254 // since pResult was "added" to pSet 1255 rWrapper.FcFontSetDestroy( pSet ); 1256 } 1257 1258 // cleanup 1259 rWrapper.FcPatternDestroy( pPattern ); 1260 1261 return bSuccess; 1262 } 1263 1264 #else // ENABLE_FONTCONFIG not defined 1265 1266 bool PrintFontManager::initFontconfig() 1267 { 1268 return false; 1269 } 1270 1271 int PrintFontManager::countFontconfigFonts( std::hash_map<rtl::OString, int, rtl::OStringHash>& ) 1272 { 1273 return 0; 1274 } 1275 1276 void PrintFontManager::deinitFontconfig() 1277 {} 1278 1279 bool PrintFontManager::addFontconfigDir( const rtl::OString& ) 1280 { 1281 return false; 1282 } 1283 1284 bool PrintFontManager::matchFont( FastPrintFontInfo&, const com::sun::star::lang::Locale& ) 1285 { 1286 return false; 1287 } 1288 1289 int PrintFontManager::FreeTypeCharIndex( void*, sal_uInt32 ) 1290 { 1291 return 0; 1292 } 1293 1294 rtl::OUString PrintFontManager::Substitute( const rtl::OUString&, 1295 rtl::OUString&, const rtl::OString&, italic::type, weight::type, width::type, pitch::type) const 1296 { 1297 rtl::OUString aName; 1298 return aName; 1299 } 1300 1301 #endif // ENABLE_FONTCONFIG 1302 1303