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