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