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