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 hierarchical 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 hierarchical 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