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