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