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