1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
34 #if OSL_DEBUG_LEVEL > 1
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
;
51 * DefaultFontConfiguration
54 static const char* getKeyType( int nKeyType
)
58 case DEFAULTFONT_CJK_DISPLAY
: return "CJK_DISPLAY";
59 case DEFAULTFONT_CJK_HEADING
: return "CJK_HEADING";
60 case DEFAULTFONT_CJK_PRESENTATION
: return "CJK_PRESENTATION";
61 case DEFAULTFONT_CJK_SPREADSHEET
: return "CJK_SPREADSHEET";
62 case DEFAULTFONT_CJK_TEXT
: return "CJK_TEXT";
63 case DEFAULTFONT_CTL_DISPLAY
: return "CTL_DISPLAY";
64 case DEFAULTFONT_CTL_HEADING
: return "CTL_HEADING";
65 case DEFAULTFONT_CTL_PRESENTATION
: return "CTL_PRESENTATION";
66 case DEFAULTFONT_CTL_SPREADSHEET
: return "CTL_SPREADSHEET";
67 case DEFAULTFONT_CTL_TEXT
: return "CTL_TEXT";
68 case DEFAULTFONT_FIXED
: return "FIXED";
69 case DEFAULTFONT_LATIN_DISPLAY
: return "LATIN_DISPLAY";
70 case DEFAULTFONT_LATIN_FIXED
: return "LATIN_FIXED";
71 case DEFAULTFONT_LATIN_HEADING
: return "LATIN_HEADING";
72 case DEFAULTFONT_LATIN_PRESENTATION
: return "LATIN_PRESENTATION";
73 case DEFAULTFONT_LATIN_SPREADSHEET
: return "LATIN_SPREADSHEET";
74 case DEFAULTFONT_LATIN_TEXT
: return "LATIN_TEXT";
75 case DEFAULTFONT_SANS
: return "SANS";
76 case DEFAULTFONT_SANS_UNICODE
: return "SANS_UNICODE";
77 case DEFAULTFONT_SERIF
: return "SERIF";
78 case DEFAULTFONT_SYMBOL
: return "SYMBOL";
79 case DEFAULTFONT_UI_FIXED
: return "UI_FIXED";
80 case DEFAULTFONT_UI_SANS
: return "UI_SANS";
82 OSL_FAIL( "unmatched type" );
89 class theDefaultFontConfiguration
90 : public rtl::Static
<DefaultFontConfiguration
,
91 theDefaultFontConfiguration
>
96 DefaultFontConfiguration
& DefaultFontConfiguration::get()
98 return theDefaultFontConfiguration::get();
101 DefaultFontConfiguration::DefaultFontConfiguration()
105 // get service provider
106 Reference
< XComponentContext
> xContext( comphelper::getProcessComponentContext() );
107 // create configuration hierachical access name
110 m_xConfigProvider
= theDefaultProvider::get( xContext
);
111 Sequence
< Any
> aArgs(1);
113 aVal
.Name
= OUString( "nodepath" );
114 aVal
.Value
<<= OUString( "/org.openoffice.VCL/DefaultFonts" );
115 aArgs
.getArray()[0] <<= aVal
;
117 Reference
< XNameAccess
>(
118 m_xConfigProvider
->createInstanceWithArguments( OUString( "com.sun.star.configuration.ConfigurationAccess" ),
121 if( m_xConfigAccess
.is() )
123 Sequence
< OUString
> aLocales
= m_xConfigAccess
->getElementNames();
124 // fill config hash with empty interfaces
125 int nLocales
= aLocales
.getLength();
126 const OUString
* pLocaleStrings
= aLocales
.getConstArray();
128 for( int i
= 0; i
< nLocales
; i
++ )
130 sal_Int32 nIndex
= 0;
131 aLoc
.Language
= pLocaleStrings
[i
].getToken( 0, sal_Unicode('-'), nIndex
).toAsciiLowerCase();
133 aLoc
.Country
= pLocaleStrings
[i
].getToken( 0, sal_Unicode('-'), nIndex
).toAsciiUpperCase();
135 aLoc
.Country
= OUString();
137 aLoc
.Variant
= pLocaleStrings
[i
].getToken( 0, sal_Unicode('-'), nIndex
).toAsciiUpperCase();
139 aLoc
.Variant
= OUString();
140 m_aConfig
[ aLoc
] = LocaleAccess();
141 m_aConfig
[ aLoc
].aConfigLocaleString
= pLocaleStrings
[i
];
145 catch (const Exception
&)
147 // configuration is awry
148 m_xConfigProvider
.clear();
149 m_xConfigAccess
.clear();
152 catch (const WrappedTargetException
&)
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"
163 DefaultFontConfiguration::~DefaultFontConfiguration()
168 m_xConfigAccess
.clear();
169 // release config provider
170 m_xConfigProvider
.clear();
173 OUString
DefaultFontConfiguration::tryLocale( const Locale
& rLocale
, const OUString
& rType
) const
177 boost::unordered_map
< Locale
, LocaleAccess
, LocaleHash
>::const_iterator it
=
178 m_aConfig
.find( rLocale
);
179 if( it
!= m_aConfig
.end() )
181 if( !it
->second
.xAccess
.is() )
185 Reference
< XNameAccess
> xNode
;
186 if ( m_xConfigAccess
->hasByName( it
->second
.aConfigLocaleString
) )
188 Any aAny
= m_xConfigAccess
->getByName( it
->second
.aConfigLocaleString
);
190 it
->second
.xAccess
= xNode
;
193 catch (const NoSuchElementException
&)
196 catch (const WrappedTargetException
&)
200 if( it
->second
.xAccess
.is() )
204 if ( it
->second
.xAccess
->hasByName( rType
) )
206 Any aAny
= it
->second
.xAccess
->getByName( rType
);
210 catch (const NoSuchElementException
&)
213 catch (const WrappedTargetException
&)
222 OUString
DefaultFontConfiguration::getDefaultFont( const Locale
& rLocale
, int nType
) const
225 aLocale
.Language
= rLocale
.Language
.toAsciiLowerCase();
226 aLocale
.Country
= rLocale
.Country
.toAsciiUpperCase();
227 aLocale
.Variant
= rLocale
.Variant
.toAsciiUpperCase();
229 OUString aType
= OUString::createFromAscii( getKeyType( nType
) );
230 OUString aRet
= tryLocale( aLocale
, aType
);
231 if( aRet
.isEmpty() && !aLocale
.Variant
.isEmpty() )
233 aLocale
.Variant
= OUString();
234 aRet
= tryLocale( aLocale
, aType
);
236 if( aRet
.isEmpty() && !aLocale
.Country
.isEmpty() )
238 aLocale
.Country
= OUString();
239 aRet
= tryLocale( aLocale
, aType
);
243 aLocale
.Language
= OUString( "en" );
244 aRet
= tryLocale( aLocale
, aType
);
249 OUString
DefaultFontConfiguration::getUserInterfaceFont( const Locale
& rLocale
) const
251 Locale aLocale
= rLocale
;
252 if( aLocale
.Language
.isEmpty() )
253 aLocale
= SvtSysLocale().GetUILanguageTag().getLocale();
255 OUString aUIFont
= getDefaultFont( aLocale
, DEFAULTFONT_UI_SANS
);
257 if( !aUIFont
.isEmpty() )
260 // fallback mechanism (either no configuration or no entry in configuration
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;"
272 // optimize font list for some locales, as long as Andale Sans UI does not support them
273 if( aLocale
.Language
== "ar" || aLocale
.Language
== "he" || aLocale
.Language
== "iw" )
275 return OUString(FALLBACKFONT_UI_SANS_ARABIC
);
277 else if ( aLocale
.Language
== "th" )
279 return OUString(FALLBACKFONT_UI_SANS_THAI
);
281 else if ( aLocale
.Language
== "ko" )
283 // we need localized names for korean fonts
284 const sal_Unicode aSunGulim
[] = { 0xC36C, 0xAD74, 0xB9BC, 0 };
285 const sal_Unicode aBaekmukGulim
[] = { 0xBC31, 0xBC35, 0xAD74, 0xB9BC, 0 };
287 OUStringBuffer aFallBackKoreanLocalized
;
288 aFallBackKoreanLocalized
.append(aSunGulim
);
289 aFallBackKoreanLocalized
.append(';');
290 aFallBackKoreanLocalized
.append(aBaekmukGulim
);
291 aFallBackKoreanLocalized
.append(";");
292 aFallBackKoreanLocalized
.append(FALLBACKFONT_UI_SANS_KOREAN
);
294 return aFallBackKoreanLocalized
.makeStringAndClear();
296 else if( aLocale
.Language
== "cs" ||
297 aLocale
.Language
== "hu" ||
298 aLocale
.Language
== "pl" ||
299 aLocale
.Language
== "ro" ||
300 aLocale
.Language
== "rm" ||
301 aLocale
.Language
== "hr" ||
302 aLocale
.Language
== "sk" ||
303 aLocale
.Language
== "sl" ||
304 aLocale
.Language
== "sb")
306 return OUString(FALLBACKFONT_UI_SANS_LATIN2
);
308 else if (MsLangId::isTraditionalChinese(aLocale
))
309 return OUString(FALLBACKFONT_UI_SANS_CHINTRD
);
310 else if (MsLangId::isSimplifiedChinese(aLocale
))
311 return OUString(FALLBACKFONT_UI_SANS_CHINSIM
);
312 else if ( aLocale
.Language
== "ja" )
314 // we need localized names for japanese fonts
315 const sal_Unicode aMSGothic
[] = { 0xFF2D, 0xFF33, ' ', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
316 const sal_Unicode aMSPGothic
[] = { 0xFF2D, 0xFF33, ' ', 0xFF30, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
317 const sal_Unicode aTLPGothic
[] = { 0x0054, 0x004C, 0x0050, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
318 const sal_Unicode aLXGothic
[] = { 0x004C, 0x0058, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
319 const sal_Unicode aKochiGothic
[] = { 0x6771, 0x98A8, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
321 OUStringBuffer aFallBackJapaneseLocalized
;
322 aFallBackJapaneseLocalized
.append("MS UI Gothic;");
323 aFallBackJapaneseLocalized
.append(FALLBACKFONT_UI_SANS_JAPANESE1
);
324 aFallBackJapaneseLocalized
.append(aMSPGothic
);
325 aFallBackJapaneseLocalized
.append(';');
326 aFallBackJapaneseLocalized
.append(aMSGothic
);
327 aFallBackJapaneseLocalized
.append(';');
328 aFallBackJapaneseLocalized
.append(aTLPGothic
);
329 aFallBackJapaneseLocalized
.append(';');
330 aFallBackJapaneseLocalized
.append(aLXGothic
);
331 aFallBackJapaneseLocalized
.append(';');
332 aFallBackJapaneseLocalized
.append(aKochiGothic
);
333 aFallBackJapaneseLocalized
.append(';');
334 aFallBackJapaneseLocalized
.append(FALLBACKFONT_UI_SANS_JAPANESE2
);
336 return aFallBackJapaneseLocalized
.makeStringAndClear();
339 return OUString(FALLBACKFONT_UI_SANS
);
342 // ------------------------------------------------------------------------------------
345 * FontSubstConfigItem::get
350 class theFontSubstConfiguration
351 : public rtl::Static
<FontSubstConfiguration
, theFontSubstConfiguration
>
356 FontSubstConfiguration
& FontSubstConfiguration::get()
358 return theFontSubstConfiguration::get();
362 * FontSubstConfigItem::FontSubstConfigItem
365 FontSubstConfiguration::FontSubstConfiguration() :
370 // get service provider
371 Reference
< XComponentContext
> xContext( comphelper::getProcessComponentContext() );
372 // create configuration hierachical access name
375 m_xConfigProvider
= theDefaultProvider::get( xContext
);
376 Sequence
< Any
> aArgs(1);
378 aVal
.Name
= OUString( "nodepath" );
379 aVal
.Value
<<= OUString( "/org.openoffice.VCL/FontSubstitutions" );
380 aArgs
.getArray()[0] <<= aVal
;
382 Reference
< XNameAccess
>(
383 m_xConfigProvider
->createInstanceWithArguments( OUString( "com.sun.star.configuration.ConfigurationAccess" ),
386 if( m_xConfigAccess
.is() )
388 Sequence
< OUString
> aLocales
= m_xConfigAccess
->getElementNames();
389 // fill config hash with empty interfaces
390 int nLocales
= aLocales
.getLength();
391 const OUString
* pLocaleStrings
= aLocales
.getConstArray();
393 for( int i
= 0; i
< nLocales
; i
++ )
395 sal_Int32 nIndex
= 0;
396 aLoc
.Language
= pLocaleStrings
[i
].getToken( 0, sal_Unicode('-'), nIndex
).toAsciiLowerCase();
398 aLoc
.Country
= pLocaleStrings
[i
].getToken( 0, sal_Unicode('-'), nIndex
).toAsciiUpperCase();
400 aLoc
.Country
= OUString();
402 aLoc
.Variant
= pLocaleStrings
[i
].getToken( 0, sal_Unicode('-'), nIndex
).toAsciiUpperCase();
404 aLoc
.Variant
= OUString();
405 m_aSubst
[ aLoc
] = LocaleSubst();
406 m_aSubst
[ aLoc
].aConfigLocaleString
= pLocaleStrings
[i
];
410 catch (const Exception
&)
412 // configuration is awry
413 m_xConfigProvider
.clear();
414 m_xConfigAccess
.clear();
417 catch (const WrappedTargetException
&)
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"
429 * FontSubstConfigItem::~FontSubstConfigItem
432 FontSubstConfiguration::~FontSubstConfiguration()
434 // release config access
435 m_xConfigAccess
.clear();
436 // release config provider
437 m_xConfigProvider
.clear();
441 * FontSubstConfigItem::getMapName
443 // =======================================================================
445 static const char* const aImplKillLeadingList
[] =
468 // -----------------------------------------------------------------------
470 static const char* const aImplKillTrailingList
[] =
483 // Scripts, for compatibility with older versions
500 // Old Printer Fontnames
520 // -----------------------------------------------------------------------
522 static const char* const aImplKillTrailingWithExceptionsList
[] =
524 "ce", "monospace", "oldface", NULL
,
529 // -----------------------------------------------------------------------
531 struct ImplFontAttrWeightSearchData
537 static ImplFontAttrWeightSearchData
const aImplWeightAttrSearchList
[] =
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
},
557 // -----------------------------------------------------------------------
559 struct ImplFontAttrWidthSearchData
565 static ImplFontAttrWidthSearchData
const aImplWidthAttrSearchList
[] =
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
},
580 struct ImplFontAttrTypeSearchData
586 static ImplFontAttrTypeSearchData
const aImplTypeAttrSearchList
[] =
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
},
635 { "extra", IMPL_FONT_ATTR_OTHERSTYLE
},
650 // -----------------------------------------------------------------------
652 static bool ImplKillLeading( String
& rName
, const char* const* ppStr
)
654 for(; *ppStr
; ++ppStr
)
656 const char* pStr
= *ppStr
;
657 const sal_Unicode
* pNameStr
= rName
.GetBuffer();
658 while ( (*pNameStr
== (sal_Unicode
)(unsigned char)*pStr
) && *pStr
)
665 xub_StrLen nLen
= sal::static_int_cast
<xub_StrLen
>(pNameStr
- rName
.GetBuffer());
666 rName
.Erase( 0, nLen
);
671 // special case for Baekmuk
672 // TODO: allow non-ASCII KillLeading list
673 const sal_Unicode
* pNameStr
= rName
.GetBuffer();
674 if( (pNameStr
[0]==0xBC31) && (pNameStr
[1]==0xBC35) )
676 xub_StrLen nLen
= (pNameStr
[2]==0x0020) ? 3 : 2;
677 rName
.Erase( 0, nLen
);
684 // -----------------------------------------------------------------------
686 static xub_StrLen
ImplIsTrailing( const String
& rName
, const char* pStr
)
688 xub_StrLen nStrLen
= static_cast<xub_StrLen
>( strlen( pStr
) );
689 if( nStrLen
>= rName
.Len() )
692 const sal_Unicode
* pEndName
= rName
.GetBuffer() + rName
.Len();
693 const sal_Unicode
* pNameStr
= pEndName
- nStrLen
;
694 do if( *(pNameStr
++) != *(pStr
++) )
701 // -----------------------------------------------------------------------
703 static bool ImplKillTrailing( String
& rName
, const char* const* ppStr
)
705 for(; *ppStr
; ++ppStr
)
707 xub_StrLen nTrailLen
= ImplIsTrailing( rName
, *ppStr
);
710 rName
.Erase( rName
.Len()-nTrailLen
);
718 // -----------------------------------------------------------------------
720 static bool ImplKillTrailingWithExceptions( String
& rName
, const char* const* ppStr
)
722 for(; *ppStr
; ++ppStr
)
724 xub_StrLen nTrailLen
= ImplIsTrailing( rName
, *ppStr
);
727 // check string match against string exceptions
729 if( ImplIsTrailing( rName
, *ppStr
) )
732 rName
.Erase( rName
.Len()-nTrailLen
);
737 // skip exception strings
745 // -----------------------------------------------------------------------
747 static sal_Bool
ImplFindAndErase( String
& rName
, const char* pStr
)
749 xub_StrLen nPos
= rName
.SearchAscii( pStr
);
750 if ( nPos
== STRING_NOTFOUND
)
753 const char* pTempStr
= pStr
;
756 rName
.Erase( nPos
, (xub_StrLen
)(pTempStr
-pStr
) );
760 // =======================================================================
762 void FontSubstConfiguration::getMapName( const String
& rOrgName
, String
& rShortName
,
763 String
& rFamilyName
, FontWeight
& rWeight
, FontWidth
& rWidth
, sal_uLong
& rType
)
765 rShortName
= rOrgName
;
767 // TODO: get rid of the crazy O(N*strlen) searches below
768 // they should be possible in O(strlen)
770 // Kill leading vendor names and other unimportant data
771 ImplKillLeading( rShortName
, aImplKillLeadingList
);
773 // Kill trailing vendor names and other unimportant data
774 ImplKillTrailing( rShortName
, aImplKillTrailingList
);
775 ImplKillTrailingWithExceptions( rShortName
, aImplKillTrailingWithExceptionsList
);
777 rFamilyName
= rShortName
;
779 // Kill attributes from the name and update the data
781 const ImplFontAttrWeightSearchData
* pWeightList
= aImplWeightAttrSearchList
;
782 while ( pWeightList
->mpStr
)
784 if ( ImplFindAndErase( rFamilyName
, pWeightList
->mpStr
) )
786 if ( (rWeight
== WEIGHT_DONTKNOW
) || (rWeight
== WEIGHT_NORMAL
) )
787 rWeight
= pWeightList
->meWeight
;
794 const ImplFontAttrWidthSearchData
* pWidthList
= aImplWidthAttrSearchList
;
795 while ( pWidthList
->mpStr
)
797 if ( ImplFindAndErase( rFamilyName
, pWidthList
->mpStr
) )
799 if ( (rWidth
== WIDTH_DONTKNOW
) || (rWidth
== WIDTH_NORMAL
) )
800 rWidth
= pWidthList
->meWidth
;
808 const ImplFontAttrTypeSearchData
* pTypeList
= aImplTypeAttrSearchList
;
809 while ( pTypeList
->mpStr
)
811 if ( ImplFindAndErase( rFamilyName
, pTypeList
->mpStr
) )
812 rType
|= pTypeList
->mnType
;
817 // TODO: also remove localized and fullwidth digits
819 while ( i
< rFamilyName
.Len() )
821 sal_Unicode c
= rFamilyName
.GetChar( i
);
822 if ( (c
>= 0x0030) && (c
<= 0x0039) )
823 rFamilyName
.Erase( i
, 1 );
830 struct StrictStringSort
: public ::std::binary_function
< const FontNameAttr
&, const FontNameAttr
&, bool >
832 bool operator()( const FontNameAttr
& rLeft
, const FontNameAttr
& rRight
)
833 { return rLeft
.Name
.CompareTo( rRight
.Name
) == COMPARE_LESS
; }
836 static const char* const pAttribNames
[] =
879 static const enum_convert pWeightNames
[] =
881 { "normal", WEIGHT_NORMAL
},
882 { "medium", WEIGHT_MEDIUM
},
883 { "bold", WEIGHT_BOLD
},
884 { "black", WEIGHT_BLACK
},
885 { "semibold", WEIGHT_SEMIBOLD
},
886 { "light", WEIGHT_LIGHT
},
887 { "semilight", WEIGHT_SEMILIGHT
},
888 { "ultrabold", WEIGHT_ULTRABOLD
},
889 { "semi", WEIGHT_SEMIBOLD
},
890 { "demi", WEIGHT_SEMIBOLD
},
891 { "heavy", WEIGHT_BLACK
},
892 { "unknown", WEIGHT_DONTKNOW
},
893 { "thin", WEIGHT_THIN
},
894 { "ultralight", WEIGHT_ULTRALIGHT
}
897 static const enum_convert pWidthNames
[] =
899 { "normal", WIDTH_NORMAL
},
900 { "condensed", WIDTH_CONDENSED
},
901 { "expanded", WIDTH_EXPANDED
},
902 { "unknown", WIDTH_DONTKNOW
},
903 { "ultracondensed", WIDTH_ULTRA_CONDENSED
},
904 { "extracondensed", WIDTH_EXTRA_CONDENSED
},
905 { "semicondensed", WIDTH_SEMI_CONDENSED
},
906 { "semiexpanded", WIDTH_SEMI_EXPANDED
},
907 { "extraexpanded", WIDTH_EXTRA_EXPANDED
},
908 { "ultraexpanded", WIDTH_ULTRA_EXPANDED
}
911 void FontSubstConfiguration::fillSubstVector( const com::sun::star::uno::Reference
< XNameAccess
> xFont
,
912 const OUString
& rType
,
913 std::vector
< String
>& rSubstVector
) const
917 Any aAny
= xFont
->getByName( rType
);
918 if( aAny
.getValueTypeClass() == TypeClass_STRING
)
920 const OUString
* pLine
= (const OUString
*)aAny
.getValue();
921 sal_Int32 nLength
= pLine
->getLength();
924 const sal_Unicode
* pStr
= pLine
->getStr();
925 sal_Int32 nTokens
= 0;
929 if( *pStr
++ == sal_Unicode(';') )
932 rSubstVector
.clear();
933 // optimize performance, heap fragmentation
934 rSubstVector
.reserve( nTokens
);
935 sal_Int32 nIndex
= 0;
936 while( nIndex
!= -1 )
938 OUString
aSubst( pLine
->getToken( 0, ';', nIndex
) );
939 if( !aSubst
.isEmpty() )
941 UniqueSubstHash::iterator aEntry
= maSubstHash
.find( aSubst
);
942 if (aEntry
!= maSubstHash
.end())
945 maSubstHash
.insert( aSubst
);
946 rSubstVector
.push_back( aSubst
);
952 catch (const NoSuchElementException
&)
955 catch (const WrappedTargetException
&)
960 FontWeight
FontSubstConfiguration::getSubstWeight( const com::sun::star::uno::Reference
< XNameAccess
> xFont
,
961 const OUString
& rType
) const
966 Any aAny
= xFont
->getByName( rType
);
967 if( aAny
.getValueTypeClass() == TypeClass_STRING
)
969 const OUString
* pLine
= (const OUString
*)aAny
.getValue();
970 if( !pLine
->isEmpty() )
972 for( weight
=SAL_N_ELEMENTS(pWeightNames
)-1; weight
>= 0; weight
-- )
973 if( pLine
->equalsIgnoreAsciiCaseAscii( pWeightNames
[weight
].pName
) )
976 #if OSL_DEBUG_LEVEL > 1
978 fprintf( stderr
, "Error: invalid weight %s\n",
979 OUStringToOString( *pLine
, RTL_TEXTENCODING_ASCII_US
).getStr() );
983 catch (const NoSuchElementException
&)
986 catch (const WrappedTargetException
&)
989 return (FontWeight
)( weight
>= 0 ? pWeightNames
[weight
].nEnum
: WEIGHT_DONTKNOW
);
992 FontWidth
FontSubstConfiguration::getSubstWidth( const com::sun::star::uno::Reference
< XNameAccess
> xFont
,
993 const OUString
& rType
) const
998 Any aAny
= xFont
->getByName( rType
);
999 if( aAny
.getValueTypeClass() == TypeClass_STRING
)
1001 const OUString
* pLine
= (const OUString
*)aAny
.getValue();
1002 if( !pLine
->isEmpty() )
1004 for( width
=SAL_N_ELEMENTS(pWidthNames
)-1; width
>= 0; width
-- )
1005 if( pLine
->equalsIgnoreAsciiCaseAscii( pWidthNames
[width
].pName
) )
1008 #if OSL_DEBUG_LEVEL > 1
1010 fprintf( stderr
, "Error: invalid width %s\n",
1011 OUStringToOString( *pLine
, RTL_TEXTENCODING_ASCII_US
).getStr() );
1015 catch (const NoSuchElementException
&)
1018 catch (const WrappedTargetException
&)
1021 return (FontWidth
)( width
>= 0 ? pWidthNames
[width
].nEnum
: WIDTH_DONTKNOW
);
1024 unsigned long FontSubstConfiguration::getSubstType( const com::sun::star::uno::Reference
< XNameAccess
> xFont
,
1025 const OUString
& rType
) const
1027 unsigned long type
= 0;
1030 Any aAny
= xFont
->getByName( rType
);
1031 if( aAny
.getValueTypeClass() == TypeClass_STRING
)
1033 const OUString
* pLine
= (const OUString
*)aAny
.getValue();
1034 if( !pLine
->isEmpty() )
1036 sal_Int32 nIndex
= 0;
1037 while( nIndex
!= -1 )
1039 String
aToken( pLine
->getToken( 0, ',', nIndex
) );
1040 for( int k
= 0; k
< 32; k
++ )
1041 if( aToken
.EqualsIgnoreCaseAscii( pAttribNames
[k
] ) )
1050 catch (const NoSuchElementException
&)
1053 catch (const WrappedTargetException
&)
1060 void FontSubstConfiguration::readLocaleSubst( const com::sun::star::lang::Locale
& rLocale
) const
1062 boost::unordered_map
< Locale
, LocaleSubst
, LocaleHash
>::const_iterator it
=
1063 m_aSubst
.find( rLocale
);
1064 if( it
!= m_aSubst
.end() )
1066 if( ! it
->second
.bConfigRead
)
1068 it
->second
.bConfigRead
= true;
1069 Reference
< XNameAccess
> xNode
;
1072 Any aAny
= m_xConfigAccess
->getByName( it
->second
.aConfigLocaleString
);
1075 catch (const NoSuchElementException
&)
1078 catch (const WrappedTargetException
&)
1083 Sequence
< OUString
> aFonts
= xNode
->getElementNames();
1084 int nFonts
= aFonts
.getLength();
1085 const OUString
* pFontNames
= aFonts
.getConstArray();
1086 // improve performance, heap fragmentation
1087 it
->second
.aSubstAttributes
.reserve( nFonts
);
1089 // strings for subst retrieval, construct only once
1090 OUString
aSubstFontsStr ( "SubstFonts" );
1091 OUString
aSubstFontsMSStr ( "SubstFontsMS" );
1092 OUString
aSubstFontsPSStr ( "SubstFontsPS" );
1093 OUString
aSubstFontsHTMLStr ( "SubstFontsHTML" );
1094 OUString
aSubstWeightStr ( "FontWeight" );
1095 OUString
aSubstWidthStr ( "FontWidth" );
1096 OUString
aSubstTypeStr ( "FontType" );
1097 for( int i
= 0; i
< nFonts
; i
++ )
1099 Reference
< XNameAccess
> xFont
;
1102 Any aAny
= xNode
->getByName( pFontNames
[i
] );
1105 catch (const NoSuchElementException
&)
1108 catch (const WrappedTargetException
&)
1113 #if OSL_DEBUG_LEVEL > 1
1114 fprintf( stderr
, "did not get font attributes for %s\n",
1115 OUStringToOString( pFontNames
[i
], RTL_TEXTENCODING_UTF8
).getStr() );
1121 // read subst attributes from config
1122 aAttr
.Name
= pFontNames
[i
];
1123 fillSubstVector( xFont
, aSubstFontsStr
, aAttr
.Substitutions
);
1124 fillSubstVector( xFont
, aSubstFontsMSStr
, aAttr
.MSSubstitutions
);
1125 fillSubstVector( xFont
, aSubstFontsPSStr
, aAttr
.PSSubstitutions
);
1126 fillSubstVector( xFont
, aSubstFontsHTMLStr
, aAttr
.HTMLSubstitutions
);
1127 aAttr
.Weight
= getSubstWeight( xFont
, aSubstWeightStr
);
1128 aAttr
.Width
= getSubstWidth( xFont
, aSubstWidthStr
);
1129 aAttr
.Type
= getSubstType( xFont
, aSubstTypeStr
);
1131 // finally insert this entry
1132 it
->second
.aSubstAttributes
.push_back( aAttr
);
1134 std::sort( it
->second
.aSubstAttributes
.begin(), it
->second
.aSubstAttributes
.end(), StrictStringSort() );
1140 const FontNameAttr
* FontSubstConfiguration::getSubstInfo( const String
& rFontName
, const Locale
& rLocale
) const
1142 if( !rFontName
.Len() )
1145 // search if a (language dep.) replacement table for the given font exists
1146 // fallback is english
1147 String
aSearchFont( rFontName
);
1148 aSearchFont
.ToLowerAscii();
1149 FontNameAttr aSearchAttr
;
1150 aSearchAttr
.Name
= aSearchFont
;
1153 aLocale
.Language
= rLocale
.Language
.toAsciiLowerCase();
1154 aLocale
.Country
= rLocale
.Country
.toAsciiUpperCase();
1155 aLocale
.Variant
= rLocale
.Variant
.toAsciiUpperCase();
1157 if( aLocale
.Language
.isEmpty() )
1158 aLocale
= SvtSysLocale().GetUILanguageTag().getLocale();
1160 while( !aLocale
.Language
.isEmpty() )
1162 boost::unordered_map
< Locale
, LocaleSubst
, LocaleHash
>::const_iterator lang
= m_aSubst
.find( aLocale
);
1163 if( lang
!= m_aSubst
.end() )
1165 if( ! lang
->second
.bConfigRead
)
1166 readLocaleSubst( aLocale
);
1167 // try to find an exact match
1168 // because the list is sorted this will also find fontnames of the form searchfontname*
1169 std::vector
< FontNameAttr
>::const_iterator it
= ::std::lower_bound( lang
->second
.aSubstAttributes
.begin(), lang
->second
.aSubstAttributes
.end(), aSearchAttr
, StrictStringSort() );
1170 if( it
!= lang
->second
.aSubstAttributes
.end())
1172 const FontNameAttr
& rFoundAttr
= *it
;
1173 // a search for "abcblack" may match with an entry for "abc"
1174 // the reverse is not a good idea (e.g. #i112731# alba->albani)
1175 if( rFoundAttr
.Name
.Len() <= aSearchFont
.Len() )
1176 if( aSearchFont
.CompareTo( rFoundAttr
.Name
, rFoundAttr
.Name
.Len() ) == COMPARE_EQUAL
)
1180 // gradually become more unspecific
1181 if( !aLocale
.Variant
.isEmpty() )
1182 aLocale
.Variant
= OUString();
1183 else if( !aLocale
.Country
.isEmpty() )
1184 aLocale
.Country
= OUString();
1185 else if( aLocale
.Language
!= "en" )
1186 aLocale
.Language
= OUString( "en" );
1188 aLocale
.Language
= OUString();
1193 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */