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_unotools.hxx" 30 #include <unotools/fontcfg.hxx> 31 #include <unotools/fontdefs.hxx> 32 #include <comphelper/processfactory.hxx> 33 #include <com/sun/star/uno/Any.hxx> 34 #include <com/sun/star/uno/Sequence.hxx> 35 #include <com/sun/star/beans/PropertyValue.hpp> 36 #include <unotools/configpathes.hxx> 37 #include <unotools/syslocale.hxx> 38 #include <rtl/ustrbuf.hxx> 39 #include <tools/debug.hxx> 40 41 #if OSL_DEBUG_LEVEL > 1 42 #include <stdio.h> 43 #endif 44 45 #include <string.h> 46 #include <list> 47 #include <algorithm> 48 49 #define DEFAULTFONT_CONFIGNODE "VCL/DefaultFonts" 50 #define SUBSTFONT_CONFIGNODE "VCL/FontSubstitutions" 51 52 using namespace rtl; 53 using namespace utl; 54 using namespace com::sun::star::uno; 55 using namespace com::sun::star::lang; 56 using namespace com::sun::star::beans; 57 using namespace com::sun::star::container; 58 59 static DefaultFontConfiguration* mpDefaultFontConfiguration = 0; 60 61 static FontSubstConfiguration* mpFontSubstConfiguration = 0; 62 63 /* 64 * DefaultFontConfiguration 65 */ 66 67 static const char* getKeyType( int nKeyType ) 68 { 69 switch( nKeyType ) 70 { 71 case DEFAULTFONT_CJK_DISPLAY: return "CJK_DISPLAY"; 72 case DEFAULTFONT_CJK_HEADING: return "CJK_HEADING"; 73 case DEFAULTFONT_CJK_PRESENTATION: return "CJK_PRESENTATION"; 74 case DEFAULTFONT_CJK_SPREADSHEET: return "CJK_SPREADSHEET"; 75 case DEFAULTFONT_CJK_TEXT: return "CJK_TEXT"; 76 case DEFAULTFONT_CTL_DISPLAY: return "CTL_DISPLAY"; 77 case DEFAULTFONT_CTL_HEADING: return "CTL_HEADING"; 78 case DEFAULTFONT_CTL_PRESENTATION: return "CTL_PRESENTATION"; 79 case DEFAULTFONT_CTL_SPREADSHEET: return "CTL_SPREADSHEET"; 80 case DEFAULTFONT_CTL_TEXT: return "CTL_TEXT"; 81 case DEFAULTFONT_FIXED: return "FIXED"; 82 case DEFAULTFONT_LATIN_DISPLAY: return "LATIN_DISPLAY"; 83 case DEFAULTFONT_LATIN_FIXED: return "LATIN_FIXED"; 84 case DEFAULTFONT_LATIN_HEADING: return "LATIN_HEADING"; 85 case DEFAULTFONT_LATIN_PRESENTATION: return "LATIN_PRESENTATION"; 86 case DEFAULTFONT_LATIN_SPREADSHEET: return "LATIN_SPREADSHEET"; 87 case DEFAULTFONT_LATIN_TEXT: return "LATIN_TEXT"; 88 case DEFAULTFONT_SANS: return "SANS"; 89 case DEFAULTFONT_SANS_UNICODE: return "SANS_UNICODE"; 90 case DEFAULTFONT_SERIF: return "SERIF"; 91 case DEFAULTFONT_SYMBOL: return "SYMBOL"; 92 case DEFAULTFONT_UI_FIXED: return "UI_FIXED"; 93 case DEFAULTFONT_UI_SANS: return "UI_SANS"; 94 default: 95 DBG_ERROR( "unmatched type" ); 96 return ""; 97 } 98 } 99 100 DefaultFontConfiguration* DefaultFontConfiguration::get() 101 { 102 if( !mpDefaultFontConfiguration ) 103 mpDefaultFontConfiguration = new DefaultFontConfiguration(); 104 return mpDefaultFontConfiguration; 105 } 106 107 DefaultFontConfiguration::DefaultFontConfiguration() 108 { 109 try 110 { 111 // get service provider 112 Reference< XMultiServiceFactory > xSMgr( comphelper::getProcessServiceFactory() ); 113 // create configuration hierachical access name 114 if( xSMgr.is() ) 115 { 116 try 117 { 118 m_xConfigProvider = 119 Reference< XMultiServiceFactory >( 120 xSMgr->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 121 "com.sun.star.configuration.ConfigurationProvider" ))), 122 UNO_QUERY ); 123 if( m_xConfigProvider.is() ) 124 { 125 Sequence< Any > aArgs(1); 126 PropertyValue aVal; 127 aVal.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) ); 128 aVal.Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.VCL/DefaultFonts" ) ); 129 aArgs.getArray()[0] <<= aVal; 130 m_xConfigAccess = 131 Reference< XNameAccess >( 132 m_xConfigProvider->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 133 "com.sun.star.configuration.ConfigurationAccess" )), 134 aArgs ), 135 UNO_QUERY ); 136 if( m_xConfigAccess.is() ) 137 { 138 Sequence< OUString > aLocales = m_xConfigAccess->getElementNames(); 139 // fill config hash with empty interfaces 140 int nLocales = aLocales.getLength(); 141 const OUString* pLocaleStrings = aLocales.getConstArray(); 142 Locale aLoc; 143 for( int i = 0; i < nLocales; i++ ) 144 { 145 sal_Int32 nIndex = 0; 146 aLoc.Language = pLocaleStrings[i].getToken( 0, sal_Unicode('-'), nIndex ).toAsciiLowerCase(); 147 if( nIndex != -1 ) 148 aLoc.Country = pLocaleStrings[i].getToken( 0, sal_Unicode('-'), nIndex ).toAsciiUpperCase(); 149 else 150 aLoc.Country = OUString(); 151 if( nIndex != -1 ) 152 aLoc.Variant = pLocaleStrings[i].getToken( 0, sal_Unicode('-'), nIndex ).toAsciiUpperCase(); 153 else 154 aLoc.Variant = OUString(); 155 m_aConfig[ aLoc ] = LocaleAccess(); 156 m_aConfig[ aLoc ].aConfigLocaleString = pLocaleStrings[i]; 157 } 158 } 159 } 160 } 161 catch( Exception& ) 162 { 163 // configuration is awry 164 m_xConfigProvider.clear(); 165 m_xConfigAccess.clear(); 166 } 167 } 168 } 169 catch( WrappedTargetException& ) 170 { 171 } 172 #if OSL_DEBUG_LEVEL > 1 173 fprintf( stderr, "config provider: %s, config access: %s\n", 174 m_xConfigProvider.is() ? "true" : "false", 175 m_xConfigAccess.is() ? "true" : "false" 176 ); 177 #endif 178 } 179 180 DefaultFontConfiguration::~DefaultFontConfiguration() 181 { 182 // release all nodes 183 m_aConfig.clear(); 184 // release top node 185 m_xConfigAccess.clear(); 186 // release config provider 187 m_xConfigProvider.clear(); 188 } 189 190 OUString DefaultFontConfiguration::tryLocale( const Locale& rLocale, const OUString& rType ) const 191 { 192 OUString aRet; 193 194 std::hash_map< Locale, LocaleAccess, LocaleHash >::const_iterator it = 195 m_aConfig.find( rLocale ); 196 if( it != m_aConfig.end() ) 197 { 198 if( !it->second.xAccess.is() ) 199 { 200 try 201 { 202 Reference< XNameAccess > xNode; 203 if ( m_xConfigAccess->hasByName( it->second.aConfigLocaleString ) ) 204 { 205 Any aAny = m_xConfigAccess->getByName( it->second.aConfigLocaleString ); 206 if( aAny >>= xNode ) 207 it->second.xAccess = xNode; 208 } 209 } 210 catch( NoSuchElementException ) 211 { 212 } 213 catch( WrappedTargetException ) 214 { 215 } 216 } 217 if( it->second.xAccess.is() ) 218 { 219 try 220 { 221 if ( it->second.xAccess->hasByName( rType ) ) 222 { 223 Any aAny = it->second.xAccess->getByName( rType ); 224 aAny >>= aRet; 225 } 226 } 227 catch( NoSuchElementException& ) 228 { 229 } 230 catch( WrappedTargetException& ) 231 { 232 } 233 } 234 } 235 236 return aRet; 237 } 238 239 OUString DefaultFontConfiguration::getDefaultFont( const Locale& rLocale, int nType ) const 240 { 241 Locale aLocale; 242 aLocale.Language = rLocale.Language.toAsciiLowerCase(); 243 aLocale.Country = rLocale.Country.toAsciiUpperCase(); 244 aLocale.Variant = rLocale.Variant.toAsciiUpperCase(); 245 246 OUString aType = OUString::createFromAscii( getKeyType( nType ) ); 247 OUString aRet = tryLocale( aLocale, aType ); 248 if( ! aRet.getLength() && aLocale.Variant.getLength() ) 249 { 250 aLocale.Variant = OUString(); 251 aRet = tryLocale( aLocale, aType ); 252 } 253 if( ! aRet.getLength() && aLocale.Country.getLength() ) 254 { 255 aLocale.Country = OUString(); 256 aRet = tryLocale( aLocale, aType ); 257 } 258 if( ! aRet.getLength() ) 259 { 260 aLocale.Language = OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) ); 261 aRet = tryLocale( aLocale, aType ); 262 } 263 return aRet; 264 } 265 266 OUString DefaultFontConfiguration::getUserInterfaceFont( const Locale& rLocale ) const 267 { 268 Locale aLocale = rLocale; 269 if( ! aLocale.Language.getLength() ) 270 aLocale = SvtSysLocale().GetUILocale(); 271 272 OUString aUIFont = getDefaultFont( aLocale, DEFAULTFONT_UI_SANS ); 273 274 if( aUIFont.getLength() ) 275 return aUIFont; 276 277 // fallback mechanism (either no configuration or no entry in configuration 278 279 #define FALLBACKFONT_UI_SANS "Andale Sans UI;Albany;Albany AMT;Tahoma;Arial Unicode MS;Arial;Nimbus Sans L;Bitstream Vera Sans;gnu-unifont;Interface User;Geneva;WarpSans;Dialog;Swiss;Lucida;Helvetica;Charcoal;Chicago;MS Sans Serif;Helv;Times;Times New Roman;Interface System" 280 #define FALLBACKFONT_UI_SANS_LATIN2 "Andale Sans UI;Albany;Albany AMT;Tahoma;Arial Unicode MS;Arial;Nimbus Sans L;Luxi Sans;Bitstream Vera Sans;Interface User;Geneva;WarpSans;Dialog;Swiss;Lucida;Helvetica;Charcoal;Chicago;MS Sans Serif;Helv;Times;Times New Roman;Interface System" 281 #define FALLBACKFONT_UI_SANS_ARABIC "Tahoma;Traditional Arabic;Simplified Arabic;Lucidasans;Lucida Sans;Supplement;Andale Sans UI;clearlyU;Interface User;Arial Unicode MS;Lucida Sans Unicode;WarpSans;Geneva;MS Sans Serif;Helv;Dialog;Albany;Lucida;Helvetica;Charcoal;Chicago;Arial;Helmet;Interface System;Sans Serif" 282 #define FALLBACKFONT_UI_SANS_THAI "OONaksit;Tahoma;Lucidasans;Arial Unicode MS" 283 #define FALLBACKFONT_UI_SANS_KOREAN "SunGulim;BaekmukGulim;Gulim;Roundgothic;Arial Unicode MS;Lucida Sans Unicode;gnu-unifont;Andale Sans UI" 284 #define FALLBACKFONT_UI_SANS_JAPANESE1 "HG-GothicB-Sun;Andale Sans UI;HG MhinchoLightJ" 285 #define FALLBACKFONT_UI_SANS_JAPANESE2 "Kochi Gothic;Gothic" 286 #define FALLBACKFONT_UI_SANS_CHINSIM "Andale Sans UI;Arial Unicode MS;ZYSong18030;AR PL SungtiL GB;AR PL KaitiM GB;SimSun;Lucida Sans Unicode;Fangsong;Hei;Song;Kai;Ming;gnu-unifont;Interface User;" 287 #define FALLBACKFONT_UI_SANS_CHINTRD "Andale Sans UI;Arial Unicode MS;AR PL Mingti2L Big5;AR PL KaitiM Big5;Kai;PMingLiU;MingLiU;Ming;Lucida Sans Unicode;gnu-unifont;Interface User;" 288 289 // we need localized names for japanese fonts 290 static sal_Unicode const aMSGothic[] = { 0xFF2D, 0xFF33, ' ', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 }; 291 static sal_Unicode const aMSPGothic[] = { 0xFF2D, 0xFF33, ' ', 0xFF30, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 }; 292 static sal_Unicode const aTLPGothic[] = { 0x0054, 0x004C, 0x0050, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 }; 293 static sal_Unicode const aLXGothic[] = { 0x004C, 0x0058, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 }; 294 static sal_Unicode const aKochiGothic[] = { 0x6771, 0x98A8, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 }; 295 296 String aFallBackJapaneseLocalized( RTL_CONSTASCII_USTRINGPARAM( "MS UI Gothic;" ) ); 297 aFallBackJapaneseLocalized += String( RTL_CONSTASCII_USTRINGPARAM( FALLBACKFONT_UI_SANS_JAPANESE1 ) ); 298 aFallBackJapaneseLocalized += String( aMSPGothic ); 299 aFallBackJapaneseLocalized += String(RTL_CONSTASCII_USTRINGPARAM( ";" ) ); 300 aFallBackJapaneseLocalized += String( aMSGothic ); 301 aFallBackJapaneseLocalized += String(RTL_CONSTASCII_USTRINGPARAM( ";" ) ); 302 aFallBackJapaneseLocalized += String( aTLPGothic ); 303 aFallBackJapaneseLocalized += String(RTL_CONSTASCII_USTRINGPARAM( ";" ) ); 304 aFallBackJapaneseLocalized += String( aLXGothic ); 305 aFallBackJapaneseLocalized += String(RTL_CONSTASCII_USTRINGPARAM( ";" ) ); 306 aFallBackJapaneseLocalized += String( aKochiGothic ); 307 aFallBackJapaneseLocalized += String(RTL_CONSTASCII_USTRINGPARAM( ";" ) ); 308 aFallBackJapaneseLocalized += String(RTL_CONSTASCII_USTRINGPARAM( FALLBACKFONT_UI_SANS_JAPANESE2 ) ); 309 static const OUString aFallBackJapanese( aFallBackJapaneseLocalized ); 310 static const OUString aFallback (RTL_CONSTASCII_USTRINGPARAM(FALLBACKFONT_UI_SANS)); 311 static const OUString aFallbackLatin2 (RTL_CONSTASCII_USTRINGPARAM(FALLBACKFONT_UI_SANS_LATIN2)); 312 static const OUString aFallBackArabic (RTL_CONSTASCII_USTRINGPARAM( FALLBACKFONT_UI_SANS_ARABIC ) ); 313 static const OUString aFallBackThai (RTL_CONSTASCII_USTRINGPARAM( FALLBACKFONT_UI_SANS_THAI ) ); 314 static const OUString aFallBackChineseSIM (RTL_CONSTASCII_USTRINGPARAM( FALLBACKFONT_UI_SANS_CHINSIM ) ); 315 static const OUString aFallBackChineseTRD (RTL_CONSTASCII_USTRINGPARAM( FALLBACKFONT_UI_SANS_CHINTRD ) ); 316 317 // we need localized names for korean fonts 318 static sal_Unicode const aSunGulim[] = { 0xC36C, 0xAD74, 0xB9BC, 0 }; 319 static sal_Unicode const aBaekmukGulim[] = { 0xBC31, 0xBC35, 0xAD74, 0xB9BC, 0 }; 320 String aFallBackKoreanLocalized( aSunGulim ); 321 aFallBackKoreanLocalized += String(RTL_CONSTASCII_USTRINGPARAM( ";" ) ); 322 aFallBackKoreanLocalized += String( aBaekmukGulim ); 323 aFallBackKoreanLocalized += String(RTL_CONSTASCII_USTRINGPARAM( ";" ) ); 324 aFallBackKoreanLocalized += String(RTL_CONSTASCII_USTRINGPARAM( FALLBACKFONT_UI_SANS_KOREAN ) ); 325 static const OUString aFallBackKorean( aFallBackKoreanLocalized ); 326 327 // optimize font list for some locales, as long as Andale Sans UI does not support them 328 if( aLocale.Language.equalsAscii( "ar" ) || 329 aLocale.Language.equalsAscii( "he" ) || 330 aLocale.Language.equalsAscii( "iw" ) ) 331 { 332 return aFallBackArabic; 333 } 334 else if( aLocale.Language.equalsAscii( "th" ) ) 335 { 336 return aFallBackThai; 337 } 338 else if( aLocale.Language.equalsAscii( "ko" ) ) 339 { 340 return aFallBackKorean; 341 } 342 else if( aLocale.Language.equalsAscii( "cs" ) || 343 aLocale.Language.equalsAscii( "hu" ) || 344 aLocale.Language.equalsAscii( "pl" ) || 345 aLocale.Language.equalsAscii( "ro" ) || 346 aLocale.Language.equalsAscii( "rm" ) || 347 aLocale.Language.equalsAscii( "hr" ) || 348 aLocale.Language.equalsAscii( "sk" ) || 349 aLocale.Language.equalsAscii( "sl" ) || 350 aLocale.Language.equalsAscii( "sb" ) ) 351 { 352 return aFallbackLatin2; 353 } 354 else if( aLocale.Language.equalsAscii( "zh" ) ) 355 { 356 if( ! aLocale.Country.equalsAscii( "cn" ) ) 357 return aFallBackChineseTRD; 358 else 359 return aFallBackChineseSIM; 360 } 361 else if( aLocale.Language.equalsAscii( "ja" ) ) 362 { 363 return aFallBackJapanese; 364 } 365 366 return aFallback; 367 } 368 369 // ------------------------------------------------------------------------------------ 370 371 /* 372 * FontSubstConfigItem::get 373 */ 374 375 FontSubstConfiguration* FontSubstConfiguration::get() 376 { 377 if( !mpFontSubstConfiguration ) 378 mpFontSubstConfiguration = new FontSubstConfiguration(); 379 return mpFontSubstConfiguration; 380 } 381 382 /* 383 * FontSubstConfigItem::FontSubstConfigItem 384 */ 385 386 FontSubstConfiguration::FontSubstConfiguration() : 387 maSubstHash( 300 ) 388 { 389 try 390 { 391 // get service provider 392 Reference< XMultiServiceFactory > xSMgr( comphelper::getProcessServiceFactory() ); 393 // create configuration hierachical access name 394 if( xSMgr.is() ) 395 { 396 try 397 { 398 m_xConfigProvider = 399 Reference< XMultiServiceFactory >( 400 xSMgr->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 401 "com.sun.star.configuration.ConfigurationProvider" ))), 402 UNO_QUERY ); 403 if( m_xConfigProvider.is() ) 404 { 405 Sequence< Any > aArgs(1); 406 PropertyValue aVal; 407 aVal.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) ); 408 aVal.Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.VCL/FontSubstitutions" ) ); 409 aArgs.getArray()[0] <<= aVal; 410 m_xConfigAccess = 411 Reference< XNameAccess >( 412 m_xConfigProvider->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 413 "com.sun.star.configuration.ConfigurationAccess" )), 414 aArgs ), 415 UNO_QUERY ); 416 if( m_xConfigAccess.is() ) 417 { 418 Sequence< OUString > aLocales = m_xConfigAccess->getElementNames(); 419 // fill config hash with empty interfaces 420 int nLocales = aLocales.getLength(); 421 const OUString* pLocaleStrings = aLocales.getConstArray(); 422 Locale aLoc; 423 for( int i = 0; i < nLocales; i++ ) 424 { 425 sal_Int32 nIndex = 0; 426 aLoc.Language = pLocaleStrings[i].getToken( 0, sal_Unicode('-'), nIndex ).toAsciiLowerCase(); 427 if( nIndex != -1 ) 428 aLoc.Country = pLocaleStrings[i].getToken( 0, sal_Unicode('-'), nIndex ).toAsciiUpperCase(); 429 else 430 aLoc.Country = OUString(); 431 if( nIndex != -1 ) 432 aLoc.Variant = pLocaleStrings[i].getToken( 0, sal_Unicode('-'), nIndex ).toAsciiUpperCase(); 433 else 434 aLoc.Variant = OUString(); 435 m_aSubst[ aLoc ] = LocaleSubst(); 436 m_aSubst[ aLoc ].aConfigLocaleString = pLocaleStrings[i]; 437 } 438 } 439 } 440 } 441 catch( Exception& ) 442 { 443 // configuration is awry 444 m_xConfigProvider.clear(); 445 m_xConfigAccess.clear(); 446 } 447 } 448 } 449 catch( WrappedTargetException& ) 450 { 451 } 452 #if OSL_DEBUG_LEVEL > 1 453 fprintf( stderr, "config provider: %s, config access: %s\n", 454 m_xConfigProvider.is() ? "true" : "false", 455 m_xConfigAccess.is() ? "true" : "false" 456 ); 457 #endif 458 } 459 460 /* 461 * FontSubstConfigItem::~FontSubstConfigItem 462 */ 463 464 FontSubstConfiguration::~FontSubstConfiguration() 465 { 466 // release config access 467 m_xConfigAccess.clear(); 468 // release config provider 469 m_xConfigProvider.clear(); 470 } 471 472 /* 473 * FontSubstConfigItem::getMapName 474 */ 475 // ======================================================================= 476 477 static const char* const aImplKillLeadingList[] = 478 { 479 "microsoft", 480 "monotype", 481 "linotype", 482 "baekmuk", 483 "adobe", 484 "nimbus", 485 "zycjk", 486 "itc", 487 "sun", 488 "amt", 489 "ms", 490 "mt", 491 "cg", 492 "hg", 493 "fz", 494 "ipa", 495 "sazanami", 496 "kochi", 497 NULL 498 }; 499 500 // ----------------------------------------------------------------------- 501 502 static const char* const aImplKillTrailingList[] = 503 { 504 "microsoft", 505 "monotype", 506 "linotype", 507 "adobe", 508 "nimbus", 509 "itc", 510 "sun", 511 "amt", 512 "ms", 513 "mt", 514 "clm", 515 // Scripts, for compatibility with older versions 516 "we", 517 "cyr", 518 "tur", 519 "wt", 520 "greek", 521 "wl", 522 // CJK extensions 523 "gb", 524 "big5", 525 "pro", 526 "z01", 527 "z02", 528 "z03", 529 "z13", 530 "b01", 531 "w3x12", 532 // Old Printer Fontnames 533 "5cpi", 534 "6cpi", 535 "7cpi", 536 "8cpi", 537 "9cpi", 538 "10cpi", 539 "11cpi", 540 "12cpi", 541 "13cpi", 542 "14cpi", 543 "15cpi", 544 "16cpi", 545 "18cpi", 546 "24cpi", 547 "scale", 548 "pc", 549 NULL 550 }; 551 552 // ----------------------------------------------------------------------- 553 554 static const char* const aImplKillTrailingWithExceptionsList[] = 555 { 556 "ce", "monospace", "oldface", NULL, 557 "ps", "caps", NULL, 558 NULL 559 }; 560 561 // ----------------------------------------------------------------------- 562 563 struct ImplFontAttrWeightSearchData 564 { 565 const char* mpStr; 566 FontWeight meWeight; 567 }; 568 569 static ImplFontAttrWeightSearchData const aImplWeightAttrSearchList[] = 570 { 571 // the attribute names are ordered by "first match wins" 572 // e.g. "semilight" should wins over "semi" 573 { "extrablack", WEIGHT_BLACK }, 574 { "ultrablack", WEIGHT_BLACK }, 575 { "ultrabold", WEIGHT_ULTRABOLD }, 576 { "semibold", WEIGHT_SEMIBOLD }, 577 { "semilight", WEIGHT_SEMILIGHT }, 578 { "semi", WEIGHT_SEMIBOLD }, 579 { "demi", WEIGHT_SEMIBOLD }, 580 { "black", WEIGHT_BLACK }, 581 { "bold", WEIGHT_BOLD }, 582 { "heavy", WEIGHT_BLACK }, 583 { "ultralight", WEIGHT_ULTRALIGHT }, 584 { "light", WEIGHT_LIGHT }, 585 { "medium", WEIGHT_MEDIUM }, 586 { NULL, WEIGHT_DONTKNOW }, 587 }; 588 589 // ----------------------------------------------------------------------- 590 591 struct ImplFontAttrWidthSearchData 592 { 593 const char* mpStr; 594 FontWidth meWidth; 595 }; 596 597 static ImplFontAttrWidthSearchData const aImplWidthAttrSearchList[] = 598 { 599 { "narrow", WIDTH_CONDENSED }, 600 { "semicondensed", WIDTH_SEMI_CONDENSED }, 601 { "ultracondensed", WIDTH_ULTRA_CONDENSED }, 602 { "semiexpanded", WIDTH_SEMI_EXPANDED }, 603 { "ultraexpanded", WIDTH_ULTRA_EXPANDED }, 604 { "expanded", WIDTH_EXPANDED }, 605 { "wide", WIDTH_ULTRA_EXPANDED }, 606 { "condensed", WIDTH_CONDENSED }, 607 { "cond", WIDTH_CONDENSED }, 608 { "cn", WIDTH_CONDENSED }, 609 { NULL, WIDTH_DONTKNOW }, 610 }; 611 612 struct ImplFontAttrTypeSearchData 613 { 614 const char* mpStr; 615 sal_uLong mnType; 616 }; 617 618 static ImplFontAttrTypeSearchData const aImplTypeAttrSearchList[] = 619 { 620 { "monotype", 0 }, 621 { "linotype", 0 }, 622 { "titling", IMPL_FONT_ATTR_TITLING }, 623 { "captitals", IMPL_FONT_ATTR_CAPITALS }, 624 { "captital", IMPL_FONT_ATTR_CAPITALS }, 625 { "caps", IMPL_FONT_ATTR_CAPITALS }, 626 { "italic", IMPL_FONT_ATTR_ITALIC }, 627 { "oblique", IMPL_FONT_ATTR_ITALIC }, 628 { "rounded", IMPL_FONT_ATTR_ROUNDED }, 629 { "outline", IMPL_FONT_ATTR_OUTLINE }, 630 { "shadow", IMPL_FONT_ATTR_SHADOW }, 631 { "handwriting", IMPL_FONT_ATTR_HANDWRITING | IMPL_FONT_ATTR_SCRIPT }, 632 { "hand", IMPL_FONT_ATTR_HANDWRITING | IMPL_FONT_ATTR_SCRIPT }, 633 { "signet", IMPL_FONT_ATTR_HANDWRITING | IMPL_FONT_ATTR_SCRIPT }, 634 { "script", IMPL_FONT_ATTR_BRUSHSCRIPT | IMPL_FONT_ATTR_SCRIPT }, 635 { "calligraphy", IMPL_FONT_ATTR_CHANCERY | IMPL_FONT_ATTR_SCRIPT }, 636 { "chancery", IMPL_FONT_ATTR_CHANCERY | IMPL_FONT_ATTR_SCRIPT }, 637 { "corsiva", IMPL_FONT_ATTR_CHANCERY | IMPL_FONT_ATTR_SCRIPT }, 638 { "gothic", IMPL_FONT_ATTR_SANSSERIF | IMPL_FONT_ATTR_GOTHIC }, 639 { "schoolbook", IMPL_FONT_ATTR_SERIF | IMPL_FONT_ATTR_SCHOOLBOOK }, 640 { "schlbk", IMPL_FONT_ATTR_SERIF | IMPL_FONT_ATTR_SCHOOLBOOK }, 641 { "typewriter", IMPL_FONT_ATTR_TYPEWRITER | IMPL_FONT_ATTR_FIXED }, 642 { "lineprinter", IMPL_FONT_ATTR_TYPEWRITER | IMPL_FONT_ATTR_FIXED }, 643 { "monospaced", IMPL_FONT_ATTR_FIXED }, 644 { "monospace", IMPL_FONT_ATTR_FIXED }, 645 { "mono", IMPL_FONT_ATTR_FIXED }, 646 { "fixed", IMPL_FONT_ATTR_FIXED }, 647 { "sansserif", IMPL_FONT_ATTR_SANSSERIF }, 648 { "sans", IMPL_FONT_ATTR_SANSSERIF }, 649 { "swiss", IMPL_FONT_ATTR_SANSSERIF }, 650 { "serif", IMPL_FONT_ATTR_SERIF }, 651 { "bright", IMPL_FONT_ATTR_SERIF }, 652 { "symbols", IMPL_FONT_ATTR_SYMBOL }, 653 { "symbol", IMPL_FONT_ATTR_SYMBOL }, 654 { "dingbats", IMPL_FONT_ATTR_SYMBOL }, 655 { "dings", IMPL_FONT_ATTR_SYMBOL }, 656 { "ding", IMPL_FONT_ATTR_SYMBOL }, 657 { "bats", IMPL_FONT_ATTR_SYMBOL }, 658 { "math", IMPL_FONT_ATTR_SYMBOL }, 659 { "oldstyle", IMPL_FONT_ATTR_OTHERSTYLE }, 660 { "oldface", IMPL_FONT_ATTR_OTHERSTYLE }, 661 { "old", IMPL_FONT_ATTR_OTHERSTYLE }, 662 { "new", 0 }, 663 { "modern", 0 }, 664 { "lucida", 0 }, 665 { "regular", 0 }, 666 { "extended", 0 }, 667 { "extra", IMPL_FONT_ATTR_OTHERSTYLE }, 668 { "ext", 0 }, 669 { "scalable", 0 }, 670 { "scale", 0 }, 671 { "nimbus", 0 }, 672 { "adobe", 0 }, 673 { "itc", 0 }, 674 { "amt", 0 }, 675 { "mt", 0 }, 676 { "ms", 0 }, 677 { "cpi", 0 }, 678 { "no", 0 }, 679 { NULL, 0 }, 680 }; 681 682 // ----------------------------------------------------------------------- 683 684 static bool ImplKillLeading( String& rName, const char* const* ppStr ) 685 { 686 for(; *ppStr; ++ppStr ) 687 { 688 const char* pStr = *ppStr; 689 const xub_Unicode* pNameStr = rName.GetBuffer(); 690 while ( (*pNameStr == (xub_Unicode)(unsigned char)*pStr) && *pStr ) 691 { 692 pNameStr++; 693 pStr++; 694 } 695 if ( !*pStr ) 696 { 697 xub_StrLen nLen = sal::static_int_cast<xub_StrLen>(pNameStr - rName.GetBuffer()); 698 rName.Erase( 0, nLen ); 699 return true; 700 } 701 } 702 703 // special case for Baekmuk 704 // TODO: allow non-ASCII KillLeading list 705 const xub_Unicode* pNameStr = rName.GetBuffer(); 706 if( (pNameStr[0]==0xBC31) && (pNameStr[1]==0xBC35) ) 707 { 708 xub_StrLen nLen = (pNameStr[2]==0x0020) ? 3 : 2; 709 rName.Erase( 0, nLen ); 710 return true; 711 } 712 713 return false; 714 } 715 716 // ----------------------------------------------------------------------- 717 718 static xub_StrLen ImplIsTrailing( const String& rName, const char* pStr ) 719 { 720 xub_StrLen nStrLen = static_cast<xub_StrLen>( strlen( pStr ) ); 721 if( nStrLen >= rName.Len() ) 722 return 0; 723 724 const xub_Unicode* pEndName = rName.GetBuffer() + rName.Len(); 725 const sal_Unicode* pNameStr = pEndName - nStrLen; 726 do if( *(pNameStr++) != *(pStr++) ) 727 return 0; 728 while( *pStr ); 729 730 return nStrLen; 731 } 732 733 // ----------------------------------------------------------------------- 734 735 static bool ImplKillTrailing( String& rName, const char* const* ppStr ) 736 { 737 for(; *ppStr; ++ppStr ) 738 { 739 xub_StrLen nTrailLen = ImplIsTrailing( rName, *ppStr ); 740 if( nTrailLen ) 741 { 742 rName.Erase( rName.Len()-nTrailLen ); 743 return true; 744 } 745 } 746 747 return false; 748 } 749 750 // ----------------------------------------------------------------------- 751 752 static bool ImplKillTrailingWithExceptions( String& rName, const char* const* ppStr ) 753 { 754 for(; *ppStr; ++ppStr ) 755 { 756 xub_StrLen nTrailLen = ImplIsTrailing( rName, *ppStr ); 757 if( nTrailLen ) 758 { 759 // check string match against string exceptions 760 while( *++ppStr ) 761 if( ImplIsTrailing( rName, *ppStr ) ) 762 return false; 763 764 rName.Erase( rName.Len()-nTrailLen ); 765 return true; 766 } 767 else 768 { 769 // skip exception strings 770 while( *++ppStr ) ; 771 } 772 } 773 774 return false; 775 } 776 777 // ----------------------------------------------------------------------- 778 779 static sal_Bool ImplFindAndErase( String& rName, const char* pStr ) 780 { 781 xub_StrLen nPos = rName.SearchAscii( pStr ); 782 if ( nPos == STRING_NOTFOUND ) 783 return sal_False; 784 785 const char* pTempStr = pStr; 786 while ( *pTempStr ) 787 pTempStr++; 788 rName.Erase( nPos, (xub_StrLen)(pTempStr-pStr) ); 789 return sal_True; 790 } 791 792 // ======================================================================= 793 794 void FontSubstConfiguration::getMapName( const String& rOrgName, String& rShortName, 795 String& rFamilyName, FontWeight& rWeight, FontWidth& rWidth, sal_uLong& rType ) 796 { 797 rShortName = rOrgName; 798 799 // TODO: get rid of the crazy O(N*strlen) searches below 800 // they should be possible in O(strlen) 801 802 // Kill leading vendor names and other unimportant data 803 ImplKillLeading( rShortName, aImplKillLeadingList ); 804 805 // Kill trailing vendor names and other unimportant data 806 ImplKillTrailing( rShortName, aImplKillTrailingList ); 807 ImplKillTrailingWithExceptions( rShortName, aImplKillTrailingWithExceptionsList ); 808 809 rFamilyName = rShortName; 810 811 // Kill attributes from the name and update the data 812 // Weight 813 const ImplFontAttrWeightSearchData* pWeightList = aImplWeightAttrSearchList; 814 while ( pWeightList->mpStr ) 815 { 816 if ( ImplFindAndErase( rFamilyName, pWeightList->mpStr ) ) 817 { 818 if ( (rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL) ) 819 rWeight = pWeightList->meWeight; 820 break; 821 } 822 pWeightList++; 823 } 824 825 // Width 826 const ImplFontAttrWidthSearchData* pWidthList = aImplWidthAttrSearchList; 827 while ( pWidthList->mpStr ) 828 { 829 if ( ImplFindAndErase( rFamilyName, pWidthList->mpStr ) ) 830 { 831 if ( (rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL) ) 832 rWidth = pWidthList->meWidth; 833 break; 834 } 835 pWidthList++; 836 } 837 838 // Type 839 rType = 0; 840 const ImplFontAttrTypeSearchData* pTypeList = aImplTypeAttrSearchList; 841 while ( pTypeList->mpStr ) 842 { 843 if ( ImplFindAndErase( rFamilyName, pTypeList->mpStr ) ) 844 rType |= pTypeList->mnType; 845 pTypeList++; 846 } 847 848 // Remove numbers 849 // TODO: also remove localized and fullwidth digits 850 xub_StrLen i = 0; 851 while ( i < rFamilyName.Len() ) 852 { 853 sal_Unicode c = rFamilyName.GetChar( i ); 854 if ( (c >= 0x0030) && (c <= 0x0039) ) 855 rFamilyName.Erase( i, 1 ); 856 else 857 i++; 858 } 859 } 860 861 862 struct StrictStringSort : public ::std::binary_function< const FontNameAttr&, const FontNameAttr&, bool > 863 { 864 bool operator()( const FontNameAttr& rLeft, const FontNameAttr& rRight ) 865 { return rLeft.Name.CompareTo( rRight.Name ) == COMPARE_LESS ; } 866 }; 867 868 static const char* const pAttribNames[] = 869 { 870 "default", 871 "standard", 872 "normal", 873 "symbol", 874 "fixed", 875 "sansserif", 876 "serif", 877 "decorative", 878 "special", 879 "italic", 880 "title", 881 "capitals", 882 "cjk", 883 "cjk_jp", 884 "cjk_sc", 885 "cjk_tc", 886 "cjk_kr", 887 "ctl", 888 "nonelatin", 889 "full", 890 "outline", 891 "shadow", 892 "rounded", 893 "typewriter", 894 "script", 895 "handwriting", 896 "chancery", 897 "comic", 898 "brushscript", 899 "gothic", 900 "schoolbook", 901 "other" 902 }; 903 904 struct enum_convert 905 { 906 const char* pName; 907 int nEnum; 908 }; 909 910 911 static const enum_convert pWeightNames[] = 912 { 913 { "normal", WEIGHT_NORMAL }, 914 { "medium", WEIGHT_MEDIUM }, 915 { "bold", WEIGHT_BOLD }, 916 { "black", WEIGHT_BLACK }, 917 { "semibold", WEIGHT_SEMIBOLD }, 918 { "light", WEIGHT_LIGHT }, 919 { "semilight", WEIGHT_SEMILIGHT }, 920 { "ultrabold", WEIGHT_ULTRABOLD }, 921 { "semi", WEIGHT_SEMIBOLD }, 922 { "demi", WEIGHT_SEMIBOLD }, 923 { "heavy", WEIGHT_BLACK }, 924 { "unknown", WEIGHT_DONTKNOW }, 925 { "thin", WEIGHT_THIN }, 926 { "ultralight", WEIGHT_ULTRALIGHT } 927 }; 928 929 static const enum_convert pWidthNames[] = 930 { 931 { "normal", WIDTH_NORMAL }, 932 { "condensed", WIDTH_CONDENSED }, 933 { "expanded", WIDTH_EXPANDED }, 934 { "unknown", WIDTH_DONTKNOW }, 935 { "ultracondensed", WIDTH_ULTRA_CONDENSED }, 936 { "extracondensed", WIDTH_EXTRA_CONDENSED }, 937 { "semicondensed", WIDTH_SEMI_CONDENSED }, 938 { "semiexpanded", WIDTH_SEMI_EXPANDED }, 939 { "extraexpanded", WIDTH_EXTRA_EXPANDED }, 940 { "ultraexpanded", WIDTH_ULTRA_EXPANDED } 941 }; 942 943 void FontSubstConfiguration::fillSubstVector( const com::sun::star::uno::Reference< XNameAccess > xFont, 944 const rtl::OUString& rType, 945 std::vector< String >& rSubstVector ) const 946 { 947 try 948 { 949 Any aAny = xFont->getByName( rType ); 950 if( aAny.getValueTypeClass() == TypeClass_STRING ) 951 { 952 const OUString* pLine = (const OUString*)aAny.getValue(); 953 sal_Int32 nIndex = 0; 954 sal_Int32 nLength = pLine->getLength(); 955 if( nLength ) 956 { 957 const sal_Unicode* pStr = pLine->getStr(); 958 sal_Int32 nTokens = 0; 959 // count tokens 960 while( nLength-- ) 961 { 962 if( *pStr++ == sal_Unicode(';') ) 963 nTokens++; 964 } 965 rSubstVector.clear(); 966 // optimize performance, heap fragmentation 967 rSubstVector.reserve( nTokens ); 968 while( nIndex != -1 ) 969 { 970 OUString aSubst( pLine->getToken( 0, ';', nIndex ) ); 971 if( aSubst.getLength() ) 972 { 973 UniqueSubstHash::iterator aEntry = maSubstHash.find( aSubst ); 974 if (aEntry != maSubstHash.end()) 975 aSubst = *aEntry; 976 else 977 maSubstHash.insert( aSubst ); 978 rSubstVector.push_back( aSubst ); 979 } 980 } 981 } 982 } 983 } 984 catch( NoSuchElementException ) 985 { 986 } 987 catch( WrappedTargetException ) 988 { 989 } 990 } 991 992 FontWeight FontSubstConfiguration::getSubstWeight( const com::sun::star::uno::Reference< XNameAccess > xFont, 993 const rtl::OUString& rType ) const 994 { 995 int weight = -1; 996 try 997 { 998 Any aAny = xFont->getByName( rType ); 999 if( aAny.getValueTypeClass() == TypeClass_STRING ) 1000 { 1001 const OUString* pLine = (const OUString*)aAny.getValue(); 1002 if( pLine->getLength() ) 1003 { 1004 for( weight=sizeof(pWeightNames)/sizeof(pWeightNames[0])-1; weight >= 0; weight-- ) 1005 if( pLine->equalsIgnoreAsciiCaseAscii( pWeightNames[weight].pName ) ) 1006 break; 1007 } 1008 #if OSL_DEBUG_LEVEL > 1 1009 if( weight < 0 ) 1010 fprintf( stderr, "Error: invalid weight %s\n", 1011 OUStringToOString( *pLine, RTL_TEXTENCODING_ASCII_US ).getStr() ); 1012 #endif 1013 } 1014 } 1015 catch( NoSuchElementException ) 1016 { 1017 } 1018 catch( WrappedTargetException ) 1019 { 1020 } 1021 return (FontWeight)( weight >= 0 ? pWeightNames[weight].nEnum : WEIGHT_DONTKNOW ); 1022 } 1023 1024 FontWidth FontSubstConfiguration::getSubstWidth( const com::sun::star::uno::Reference< XNameAccess > xFont, 1025 const rtl::OUString& rType ) const 1026 { 1027 int width = -1; 1028 try 1029 { 1030 Any aAny = xFont->getByName( rType ); 1031 if( aAny.getValueTypeClass() == TypeClass_STRING ) 1032 { 1033 const OUString* pLine = (const OUString*)aAny.getValue(); 1034 if( pLine->getLength() ) 1035 { 1036 for( width=sizeof(pWidthNames)/sizeof(pWidthNames[0])-1; width >= 0; width-- ) 1037 if( pLine->equalsIgnoreAsciiCaseAscii( pWidthNames[width].pName ) ) 1038 break; 1039 } 1040 #if OSL_DEBUG_LEVEL > 1 1041 if( width < 0 ) 1042 fprintf( stderr, "Error: invalid width %s\n", 1043 OUStringToOString( *pLine, RTL_TEXTENCODING_ASCII_US ).getStr() ); 1044 #endif 1045 } 1046 } 1047 catch( NoSuchElementException ) 1048 { 1049 } 1050 catch( WrappedTargetException ) 1051 { 1052 } 1053 return (FontWidth)( width >= 0 ? pWidthNames[width].nEnum : WIDTH_DONTKNOW ); 1054 } 1055 1056 unsigned long FontSubstConfiguration::getSubstType( const com::sun::star::uno::Reference< XNameAccess > xFont, 1057 const rtl::OUString& rType ) const 1058 { 1059 unsigned long type = 0; 1060 try 1061 { 1062 Any aAny = xFont->getByName( rType ); 1063 if( aAny.getValueTypeClass() == TypeClass_STRING ) 1064 { 1065 const OUString* pLine = (const OUString*)aAny.getValue(); 1066 if( pLine->getLength() ) 1067 { 1068 sal_Int32 nIndex = 0; 1069 while( nIndex != -1 ) 1070 { 1071 String aToken( pLine->getToken( 0, ',', nIndex ) ); 1072 for( int k = 0; k < 32; k++ ) 1073 if( aToken.EqualsIgnoreCaseAscii( pAttribNames[k] ) ) 1074 { 1075 type |= 1 << k; 1076 break; 1077 } 1078 } 1079 } 1080 } 1081 } 1082 catch( NoSuchElementException ) 1083 { 1084 } 1085 catch( WrappedTargetException ) 1086 { 1087 } 1088 1089 return type; 1090 } 1091 1092 void FontSubstConfiguration::readLocaleSubst( const com::sun::star::lang::Locale& rLocale ) const 1093 { 1094 std::hash_map< Locale, LocaleSubst, LocaleHash >::const_iterator it = 1095 m_aSubst.find( rLocale ); 1096 if( it != m_aSubst.end() ) 1097 { 1098 if( ! it->second.bConfigRead ) 1099 { 1100 it->second.bConfigRead = true; 1101 Reference< XNameAccess > xNode; 1102 try 1103 { 1104 Any aAny = m_xConfigAccess->getByName( it->second.aConfigLocaleString ); 1105 aAny >>= xNode; 1106 } 1107 catch( NoSuchElementException ) 1108 { 1109 } 1110 catch( WrappedTargetException ) 1111 { 1112 } 1113 if( xNode.is() ) 1114 { 1115 Sequence< OUString > aFonts = xNode->getElementNames(); 1116 int nFonts = aFonts.getLength(); 1117 const OUString* pFontNames = aFonts.getConstArray(); 1118 // improve performance, heap fragmentation 1119 it->second.aSubstAttributes.reserve( nFonts ); 1120 1121 // strings for subst retrieval, construct only once 1122 OUString aSubstFontsStr ( RTL_CONSTASCII_USTRINGPARAM( "SubstFonts" ) ); 1123 OUString aSubstFontsMSStr ( RTL_CONSTASCII_USTRINGPARAM( "SubstFontsMS" ) ); 1124 OUString aSubstFontsPSStr ( RTL_CONSTASCII_USTRINGPARAM( "SubstFontsPS" ) ); 1125 OUString aSubstFontsHTMLStr ( RTL_CONSTASCII_USTRINGPARAM( "SubstFontsHTML" ) ); 1126 OUString aSubstWeightStr ( RTL_CONSTASCII_USTRINGPARAM( "FontWeight" ) ); 1127 OUString aSubstWidthStr ( RTL_CONSTASCII_USTRINGPARAM( "FontWidth" ) ); 1128 OUString aSubstTypeStr ( RTL_CONSTASCII_USTRINGPARAM( "FontType" ) ); 1129 for( int i = 0; i < nFonts; i++ ) 1130 { 1131 Reference< XNameAccess > xFont; 1132 try 1133 { 1134 Any aAny = xNode->getByName( pFontNames[i] ); 1135 aAny >>= xFont; 1136 } 1137 catch( NoSuchElementException ) 1138 { 1139 } 1140 catch( WrappedTargetException ) 1141 { 1142 } 1143 if( ! xFont.is() ) 1144 { 1145 #if OSL_DEBUG_LEVEL > 1 1146 fprintf( stderr, "did not get font attributes for %s\n", 1147 OUStringToOString( pFontNames[i], RTL_TEXTENCODING_UTF8 ).getStr() ); 1148 #endif 1149 continue; 1150 } 1151 1152 FontNameAttr aAttr; 1153 // read subst attributes from config 1154 aAttr.Name = pFontNames[i]; 1155 fillSubstVector( xFont, aSubstFontsStr, aAttr.Substitutions ); 1156 fillSubstVector( xFont, aSubstFontsMSStr, aAttr.MSSubstitutions ); 1157 fillSubstVector( xFont, aSubstFontsPSStr, aAttr.PSSubstitutions ); 1158 fillSubstVector( xFont, aSubstFontsHTMLStr, aAttr.HTMLSubstitutions ); 1159 aAttr.Weight = getSubstWeight( xFont, aSubstWeightStr ); 1160 aAttr.Width = getSubstWidth( xFont, aSubstWidthStr ); 1161 aAttr.Type = getSubstType( xFont, aSubstTypeStr ); 1162 1163 // finally insert this entry 1164 it->second.aSubstAttributes.push_back( aAttr ); 1165 } 1166 std::sort( it->second.aSubstAttributes.begin(), it->second.aSubstAttributes.end(), StrictStringSort() ); 1167 } 1168 } 1169 } 1170 } 1171 1172 const FontNameAttr* FontSubstConfiguration::getSubstInfo( const String& rFontName, const Locale& rLocale ) const 1173 { 1174 if( !rFontName.Len() ) 1175 return NULL; 1176 1177 // search if a (language dep.) replacement table for the given font exists 1178 // fallback is english 1179 String aSearchFont( rFontName ); 1180 aSearchFont.ToLowerAscii(); 1181 FontNameAttr aSearchAttr; 1182 aSearchAttr.Name = aSearchFont; 1183 1184 Locale aLocale; 1185 aLocale.Language = rLocale.Language.toAsciiLowerCase(); 1186 aLocale.Country = rLocale.Country.toAsciiUpperCase(); 1187 aLocale.Variant = rLocale.Variant.toAsciiUpperCase(); 1188 1189 if( ! aLocale.Language.getLength() ) 1190 aLocale = SvtSysLocale().GetUILocale(); 1191 1192 while( aLocale.Language.getLength() ) 1193 { 1194 std::hash_map< Locale, LocaleSubst, LocaleHash >::const_iterator lang = m_aSubst.find( aLocale ); 1195 if( lang != m_aSubst.end() ) 1196 { 1197 if( ! lang->second.bConfigRead ) 1198 readLocaleSubst( aLocale ); 1199 // try to find an exact match 1200 // because the list is sorted this will also find fontnames of the form searchfontname* 1201 std::vector< FontNameAttr >::const_iterator it = ::std::lower_bound( lang->second.aSubstAttributes.begin(), lang->second.aSubstAttributes.end(), aSearchAttr, StrictStringSort() ); 1202 if( it != lang->second.aSubstAttributes.end()) 1203 { 1204 const FontNameAttr& rFoundAttr = *it; 1205 // a search for "abcblack" may match with an entry for "abc" 1206 // the reverse is not a good idea (e.g. #i112731# alba->albani) 1207 if( rFoundAttr.Name.Len() <= aSearchFont.Len() ) 1208 if( aSearchFont.CompareTo( rFoundAttr.Name, rFoundAttr.Name.Len() ) == COMPARE_EQUAL ) 1209 return &rFoundAttr; 1210 } 1211 } 1212 // gradually become more unspecific 1213 if( aLocale.Variant.getLength() ) 1214 aLocale.Variant = OUString(); 1215 else if( aLocale.Country.getLength() ) 1216 aLocale.Country = OUString(); 1217 else if( ! aLocale.Language.equalsAscii( "en" ) ) 1218 aLocale.Language = OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) ); 1219 else 1220 aLocale.Language = OUString(); 1221 } 1222 return NULL; 1223 } 1224 1225