xref: /aoo41x/main/unotools/source/config/fontcfg.cxx (revision b5088357)
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 
getKeyType(int nKeyType)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 
get()96 DefaultFontConfiguration* DefaultFontConfiguration::get()
97 {
98     if( !mpDefaultFontConfiguration )
99         mpDefaultFontConfiguration = new DefaultFontConfiguration();
100     return mpDefaultFontConfiguration;
101 }
102 
DefaultFontConfiguration()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 
~DefaultFontConfiguration()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 
tryLocale(const Locale & rLocale,const OUString & rType) const186 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 
getDefaultFont(const Locale & rLocale,int nType) const235 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 
getUserInterfaceFont(const Locale & rLocale) const262 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 
get()371 FontSubstConfiguration* FontSubstConfiguration::get()
372 {
373     if( !mpFontSubstConfiguration )
374         mpFontSubstConfiguration = new FontSubstConfiguration();
375     return mpFontSubstConfiguration;
376 }
377 
378 /*
379  *  FontSubstConfigItem::FontSubstConfigItem
380  */
381 
FontSubstConfiguration()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 
~FontSubstConfiguration()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 
ImplKillLeading(String & rName,const char * const * ppStr)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 
ImplIsTrailing(const String & rName,const char * pStr)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 
ImplKillTrailing(String & rName,const char * const * ppStr)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 
ImplKillTrailingWithExceptions(String & rName,const char * const * ppStr)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 
ImplFindAndErase(String & rName,const char * pStr)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 
getMapName(const String & rOrgName,String & rShortName,String & rFamilyName,FontWeight & rWeight,FontWidth & rWidth,sal_uLong & rType)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 {
operator ()StrictStringSort860     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 
fillSubstVector(const com::sun::star::uno::Reference<XNameAccess> xFont,const rtl::OUString & rType,std::vector<String> & rSubstVector) const939 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 
getSubstWeight(const com::sun::star::uno::Reference<XNameAccess> xFont,const rtl::OUString & rType) const988 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 
getSubstWidth(const com::sun::star::uno::Reference<XNameAccess> xFont,const rtl::OUString & rType) const1020 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 
getSubstType(const com::sun::star::uno::Reference<XNameAccess> xFont,const rtl::OUString & rType) const1052 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 
readLocaleSubst(const com::sun::star::lang::Locale & rLocale) const1088 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 
getSubstInfo(const String & rFontName,const Locale & rLocale) const1168 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