Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / source / font / PhysicalFontCollection.cxx
blobb10f3c29592639efb4fc494d5d0d0896c88faf19
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <memory>
21 #include <map>
23 #include <i18nlangtag/mslangid.hxx>
24 #include <unotools/configmgr.hxx>
25 #include <unotools/fontdefs.hxx>
27 #include "outdev.h"
28 #include "PhysicalFontCollection.hxx"
30 static ImplFontAttrs lcl_IsCJKFont( const OUString& rFontName )
32 // Test, if Fontname includes CJK characters --> In this case we
33 // mention that it is a CJK font
34 for(int i = 0; i < rFontName.getLength(); i++)
36 const sal_Unicode ch = rFontName[i];
37 // japanese
38 if ( ((ch >= 0x3040) && (ch <= 0x30FF)) ||
39 ((ch >= 0x3190) && (ch <= 0x319F)) )
40 return ImplFontAttrs::CJK|ImplFontAttrs::CJK_JP;
42 // korean
43 if ( ((ch >= 0xAC00) && (ch <= 0xD7AF)) ||
44 ((ch >= 0x3130) && (ch <= 0x318F)) ||
45 ((ch >= 0x1100) && (ch <= 0x11FF)) )
46 return ImplFontAttrs::CJK|ImplFontAttrs::CJK_KR;
48 // chinese
49 if ( ((ch >= 0x3400) && (ch <= 0x9FFF)) )
50 return ImplFontAttrs::CJK|ImplFontAttrs::CJK_TC|ImplFontAttrs::CJK_SC;
52 // cjk
53 if ( ((ch >= 0x3000) && (ch <= 0xD7AF)) ||
54 ((ch >= 0xFF00) && (ch <= 0xFFEE)) )
55 return ImplFontAttrs::CJK;
59 return ImplFontAttrs::None;
62 PhysicalFontCollection::PhysicalFontCollection()
63 : mbMatchData( false )
64 , mbMapNames( false )
65 , mpPreMatchHook( nullptr )
66 , mpFallbackHook( nullptr )
67 , mpFallbackList( nullptr )
68 , mnFallbackCount( -1 )
71 PhysicalFontCollection::~PhysicalFontCollection()
73 Clear();
76 void PhysicalFontCollection::SetPreMatchHook( ImplPreMatchFontSubstitution* pHook )
78 mpPreMatchHook = pHook;
81 void PhysicalFontCollection::SetFallbackHook( ImplGlyphFallbackFontSubstitution* pHook )
83 mpFallbackHook = pHook;
86 void PhysicalFontCollection::Clear()
88 // remove fallback lists
89 delete[] mpFallbackList;
90 mpFallbackList = nullptr;
91 mnFallbackCount = -1;
93 // clear all entries in the device font list
94 PhysicalFontFamilies::iterator it = maPhysicalFontFamilies.begin();
95 for(; it != maPhysicalFontFamilies.end(); ++it )
97 PhysicalFontFamily* pEntry = (*it).second;
98 delete pEntry;
101 maPhysicalFontFamilies.clear();
103 // match data must be recalculated too
104 mbMatchData = false;
107 void PhysicalFontCollection::ImplInitGenericGlyphFallback() const
109 // normalized family names of fonts suited for glyph fallback
110 // if a font is available related fonts can be ignored
111 // TODO: implement dynamic lists
112 static const char* aGlyphFallbackList[] = {
113 // empty strings separate the names of unrelated fonts
114 "eudc", "",
115 "arialunicodems", "cyberbit", "code2000", "",
116 "andalesansui", "",
117 "starsymbol", "opensymbol", "",
118 "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "",
119 "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "",
120 "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "",
121 "tahoma", "dejavusans", "timesnewroman", "liberationsans", "",
122 "shree", "mangal", "",
123 "raavi", "shruti", "tunga", "",
124 "latha", "gautami", "kartika", "vrinda", "",
125 "shayyalmt", "naskmt", "scheherazade", "",
126 "david", "nachlieli", "lucidagrande", "",
127 "norasi", "angsanaupc", "",
128 "khmerossystem", "",
129 "muktinarrow", "",
130 "phetsarathot", "",
131 "padauk", "pinlonmyanmar", "",
132 "iskoolapota", "lklug", "",
133 nullptr
136 bool bHasEudc = false;
137 int nMaxLevel = 0;
138 int nBestQuality = 0;
139 PhysicalFontFamily** pFallbackList = nullptr;
141 for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames )
143 // advance to next sub-list when end-of-sublist marker
144 if( !**ppNames ) // #i46456# check for empty string, i.e., deref string itself not only ptr to it
146 if( nBestQuality > 0 )
147 if( ++nMaxLevel >= MAX_GLYPHFALLBACK )
148 break;
150 if( !ppNames[1] )
151 break;
153 nBestQuality = 0;
154 continue;
157 // test if the glyph fallback candidate font is available and scalable
158 OUString aTokenName( *ppNames, strlen(*ppNames), RTL_TEXTENCODING_UTF8 );
159 PhysicalFontFamily* pFallbackFont = FindFontFamily( aTokenName );
161 if( !pFallbackFont )
162 continue;
164 // keep the best font of the glyph fallback sub-list
165 if( nBestQuality < pFallbackFont->GetMinQuality() )
167 nBestQuality = pFallbackFont->GetMinQuality();
168 // store available glyph fallback fonts
169 if( !pFallbackList )
170 pFallbackList = new PhysicalFontFamily*[ MAX_GLYPHFALLBACK ];
172 pFallbackList[ nMaxLevel ] = pFallbackFont;
173 if( !bHasEudc && !nMaxLevel )
174 bHasEudc = !strncmp( *ppNames, "eudc", 5 );
178 mnFallbackCount = nMaxLevel;
179 mpFallbackList = pFallbackList;
182 PhysicalFontFamily* PhysicalFontCollection::GetGlyphFallbackFont( FontSelectPattern& rFontSelData,
183 OUString& rMissingCodes,
184 int nFallbackLevel ) const
186 PhysicalFontFamily* pFallbackData = nullptr;
188 // find a matching font candidate for platform specific glyph fallback
189 if( mpFallbackHook )
191 // check cache for the first matching entry
192 // to avoid calling the expensive fallback hook (#i83491#)
193 sal_UCS4 cChar = 0;
194 bool bCached = true;
195 sal_Int32 nStrIndex = 0;
196 while( nStrIndex < rMissingCodes.getLength() )
198 cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
199 bCached = rFontSelData.mpFontInstance->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName );
201 // ignore entries which don't have a fallback
202 if( !bCached || !rFontSelData.maSearchName.isEmpty() )
203 break;
206 if( bCached )
208 // there is a matching fallback in the cache
209 // so update rMissingCodes with codepoints not yet resolved by this fallback
210 int nRemainingLength = 0;
211 std::unique_ptr<sal_UCS4[]> const pRemainingCodes(new sal_UCS4[rMissingCodes.getLength()]);
212 OUString aFontName;
214 while( nStrIndex < rMissingCodes.getLength() )
216 cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
217 bCached = rFontSelData.mpFontInstance->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName );
218 if( !bCached || (rFontSelData.maSearchName != aFontName) )
219 pRemainingCodes[ nRemainingLength++ ] = cChar;
221 rMissingCodes = OUString( pRemainingCodes.get(), nRemainingLength );
223 else
225 OUString aOldMissingCodes = rMissingCodes;
227 // call the hook to query the best matching glyph fallback font
228 if( mpFallbackHook->FindFontSubstitute( rFontSelData, rMissingCodes ) )
229 // apply outdev3.cxx specific fontname normalization
230 rFontSelData.maSearchName = GetEnglishSearchFontName( rFontSelData.maSearchName );
231 else
232 rFontSelData.maSearchName.clear();
234 // See fdo#32665 for an example. FreeSerif that has glyphs in normal
235 // font, but not in the italic or bold version
236 bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix();
238 // Cache the result even if there was no match, unless its from part of a font for which the properties need
239 // to be faked. We need to rework this cache to take into account that fontconfig can return different fonts
240 // for different input sizes, weights, etc. Basically the cache is way to naive
241 if (!bSubSetOfFontRequiresPropertyFaking)
243 for(;;)
245 if( !rFontSelData.mpFontInstance->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
246 rFontSelData.mpFontInstance->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
247 if( nStrIndex >= aOldMissingCodes.getLength() )
248 break;
249 cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
251 if( !rFontSelData.maSearchName.isEmpty() )
253 // remove cache entries that were still not resolved
254 for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
256 cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
257 rFontSelData.mpFontInstance->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
263 // find the matching device font
264 if( !rFontSelData.maSearchName.isEmpty() )
265 pFallbackData = FindFontFamily( rFontSelData.maSearchName );
268 // else find a matching font candidate for generic glyph fallback
269 if( !pFallbackData )
271 // initialize font candidates for generic glyph fallback if needed
272 if( mnFallbackCount < 0 )
273 ImplInitGenericGlyphFallback();
275 // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook
276 if( nFallbackLevel < mnFallbackCount )
277 pFallbackData = mpFallbackList[ nFallbackLevel ];
280 return pFallbackData;
283 void PhysicalFontCollection::Add( PhysicalFontFace* pNewData )
285 OUString aSearchName = GetEnglishSearchFontName( pNewData->GetFamilyName() );
287 PhysicalFontFamily* pFoundData = FindOrCreateFontFamily( aSearchName );
289 bool bKeepNewData = pFoundData->AddFontFace( pNewData );
291 if( !bKeepNewData )
292 delete pNewData;
295 // find the font from the normalized font family name
296 PhysicalFontFamily* PhysicalFontCollection::ImplFindFontFamilyBySearchName( const OUString& rSearchName ) const
298 // must be called with a normalized name.
299 assert( GetEnglishSearchFontName( rSearchName ) == rSearchName );
301 PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( rSearchName );
302 if( it == maPhysicalFontFamilies.end() )
303 return nullptr;
305 PhysicalFontFamily* pFoundData = (*it).second;
306 return pFoundData;
309 PhysicalFontFamily* PhysicalFontCollection::ImplFindFontFamilyByAliasName(const OUString& rSearchName,
310 const OUString& rShortName) const
312 // short circuit for impossible font name alias
313 if (rSearchName.isEmpty())
314 return nullptr;
316 // short circuit if no alias names are available
317 if (!mbMapNames)
318 return nullptr;
320 // use the font's alias names to find the font
321 // TODO: get rid of linear search
322 PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
323 while( it != maPhysicalFontFamilies.end() )
325 PhysicalFontFamily* pData = (*it).second;
326 if( pData->GetAliasNames().isEmpty() )
327 continue;
329 // if one alias name matches we found a matching font
330 OUString aTempName;
331 sal_Int32 nIndex = 0;
335 aTempName = GetNextFontToken( pData->GetAliasNames(), nIndex );
336 // Test, if the Font name match with one of the mapping names
337 if ( (aTempName == rSearchName) || (aTempName == rShortName) )
338 return pData;
340 while ( nIndex != -1 );
343 return nullptr;
346 PhysicalFontFamily* PhysicalFontCollection::FindFontFamily( const OUString& rFontName ) const
348 return ImplFindFontFamilyBySearchName( GetEnglishSearchFontName( rFontName ) );
351 PhysicalFontFamily *PhysicalFontCollection::FindOrCreateFontFamily( const OUString &rFamilyName )
353 PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( rFamilyName );
354 PhysicalFontFamily* pFoundData = nullptr;
356 if( it != maPhysicalFontFamilies.end() )
357 pFoundData = (*it).second;
359 if( !pFoundData )
361 pFoundData = new PhysicalFontFamily( rFamilyName );
362 maPhysicalFontFamilies[ rFamilyName ] = pFoundData;
365 return pFoundData;
368 PhysicalFontFamily* PhysicalFontCollection::FindFontFamilyByTokenNames(const OUString& rTokenStr) const
370 PhysicalFontFamily* pFoundData = nullptr;
372 // use normalized font name tokens to find the font
373 for( sal_Int32 nTokenPos = 0; nTokenPos != -1; )
375 OUString aFamilyName = GetNextFontToken( rTokenStr, nTokenPos );
376 if( aFamilyName.isEmpty() )
377 continue;
379 pFoundData = FindFontFamily( aFamilyName );
381 if( pFoundData )
382 break;
385 return pFoundData;
388 PhysicalFontFamily* PhysicalFontCollection::ImplFindFontFamilyBySubstFontAttr( const utl::FontNameAttr& rFontAttr ) const
390 PhysicalFontFamily* pFoundData = nullptr;
392 // use the font substitutions suggested by the FontNameAttr to find the font
393 ::std::vector< OUString >::const_iterator it = rFontAttr.Substitutions.begin();
394 for(; it != rFontAttr.Substitutions.end(); ++it )
396 pFoundData = FindFontFamily( *it );
397 if( pFoundData )
398 return pFoundData;
401 // use known attributes from the configuration to find a matching substitute
402 const ImplFontAttrs nSearchType = rFontAttr.Type;
403 if( nSearchType != ImplFontAttrs::None )
405 const FontWeight eSearchWeight = rFontAttr.Weight;
406 const FontWidth eSearchWidth = rFontAttr.Width;
407 const FontItalic eSearchSlant = ITALIC_DONTKNOW;
408 const OUString aSearchName;
410 pFoundData = FindFontFamilyByAttributes( nSearchType,
411 eSearchWeight, eSearchWidth, eSearchSlant, aSearchName );
413 if( pFoundData )
414 return pFoundData;
417 return nullptr;
420 void PhysicalFontCollection::ImplInitMatchData() const
422 // short circuit if already done
423 if( mbMatchData )
424 return;
425 mbMatchData = true;
427 if (utl::ConfigManager::IsAvoidConfig())
428 return;
430 // calculate MatchData for all entries
431 const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
433 PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
434 for(; it != maPhysicalFontFamilies.end(); ++it )
436 const OUString& rSearchName = (*it).first;
437 PhysicalFontFamily* pEntry = (*it).second;
439 pEntry->InitMatchData( rFontSubst, rSearchName );
443 PhysicalFontFamily* PhysicalFontCollection::FindFontFamilyByAttributes( ImplFontAttrs nSearchType,
444 FontWeight eSearchWeight,
445 FontWidth eSearchWidth,
446 FontItalic eSearchItalic,
447 const OUString& rSearchFamilyName ) const
449 if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) )
450 nSearchType |= ImplFontAttrs::Italic;
452 // don't bother to match attributes if the attributes aren't worth matching
453 if( nSearchType == ImplFontAttrs::None
454 && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL))
455 && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) )
456 return nullptr;
458 ImplInitMatchData();
459 PhysicalFontFamily* pFoundData = nullptr;
461 long nBestMatch = 40000;
462 ImplFontAttrs nBestType = ImplFontAttrs::None;
464 PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
465 for(; it != maPhysicalFontFamilies.end(); ++it )
467 PhysicalFontFamily* pData = (*it).second;
469 // Get all information about the matching font
470 ImplFontAttrs nMatchType = pData->GetMatchType();
471 FontWeight eMatchWeight= pData->GetMatchWeight();
472 FontWidth eMatchWidth = pData->GetMatchWidth();
474 // Calculate Match Value
475 // 1000000000
476 // 100000000
477 // 10000000 CJK, CTL, None-Latin, Symbol
478 // 1000000 FamilyName, Script, Fixed, -Special, -Decorative,
479 // Titling, Capitals, Outline, Shadow
480 // 100000 Match FamilyName, Serif, SansSerif, Italic,
481 // Width, Weight
482 // 10000 Scalable, Standard, Default,
483 // full, Normal, Knownfont,
484 // Otherstyle, +Special, +Decorative,
485 // 1000 Typewriter, Rounded, Gothic, Schollbook
486 // 100
487 long nTestMatch = 0;
489 // test CJK script attributes
490 if ( nSearchType & ImplFontAttrs::CJK )
492 // Matching language
493 if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::CJK_AllLang) )
494 nTestMatch += 10000000*3;
495 if( nMatchType & ImplFontAttrs::CJK )
496 nTestMatch += 10000000*2;
497 if( nMatchType & ImplFontAttrs::Full )
498 nTestMatch += 10000000;
500 else if ( nMatchType & ImplFontAttrs::CJK )
502 nTestMatch -= 10000000;
505 // test CTL script attributes
506 if( nSearchType & ImplFontAttrs::CTL )
508 if( nMatchType & ImplFontAttrs::CTL )
509 nTestMatch += 10000000*2;
510 if( nMatchType & ImplFontAttrs::Full )
511 nTestMatch += 10000000;
513 else if ( nMatchType & ImplFontAttrs::CTL )
515 nTestMatch -= 10000000;
518 // test LATIN script attributes
519 if( nSearchType & ImplFontAttrs::NoneLatin )
521 if( nMatchType & ImplFontAttrs::NoneLatin )
522 nTestMatch += 10000000*2;
523 if( nMatchType & ImplFontAttrs::Full )
524 nTestMatch += 10000000;
527 // test SYMBOL attributes
528 if ( nSearchType & ImplFontAttrs::Symbol )
530 const OUString& rSearchName = it->first;
531 // prefer some special known symbol fonts
532 if ( rSearchName == "starsymbol" )
534 nTestMatch += 10000000*6+(10000*3);
536 else if ( rSearchName == "opensymbol" )
538 nTestMatch += 10000000*6;
540 else if ( rSearchName == "starbats" ||
541 rSearchName == "wingdings" ||
542 rSearchName == "monotypesorts" ||
543 rSearchName == "dingbats" ||
544 rSearchName == "zapfdingbats" )
546 nTestMatch += 10000000*5;
548 else if ( pData->GetTypeFaces() & FontTypeFaces::Symbol )
550 nTestMatch += 10000000*4;
552 else
554 if( nMatchType & ImplFontAttrs::Symbol )
555 nTestMatch += 10000000*2;
556 if( nMatchType & ImplFontAttrs::Full )
557 nTestMatch += 10000000;
560 else if ( (pData->GetTypeFaces() & (FontTypeFaces::Symbol | FontTypeFaces::NoneSymbol)) == FontTypeFaces::Symbol )
562 nTestMatch -= 10000000;
564 else if ( nMatchType & ImplFontAttrs::Symbol )
566 nTestMatch -= 10000;
569 // match stripped family name
570 if( !rSearchFamilyName.isEmpty() && (rSearchFamilyName == pData->GetMatchFamilyName()) )
572 nTestMatch += 1000000*3;
575 // match ALLSCRIPT? attribute
576 if( nSearchType & ImplFontAttrs::AllScript )
578 if( nMatchType & ImplFontAttrs::AllScript )
580 nTestMatch += 1000000*2;
582 if( nSearchType & ImplFontAttrs::AllSubscript )
584 if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::AllSubscript) )
585 nTestMatch += 1000000*2;
586 if( ImplFontAttrs::None != ((nSearchType ^ nMatchType) & ImplFontAttrs::BrushScript) )
587 nTestMatch -= 1000000;
590 else if( nMatchType & ImplFontAttrs::AllScript )
592 nTestMatch -= 1000000;
595 // test MONOSPACE+TYPEWRITER attributes
596 if( nSearchType & ImplFontAttrs::Fixed )
598 if( nMatchType & ImplFontAttrs::Fixed )
599 nTestMatch += 1000000*2;
600 // a typewriter attribute is even better
601 if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Typewriter) )
602 nTestMatch += 10000*2;
604 else if( nMatchType & ImplFontAttrs::Fixed )
606 nTestMatch -= 1000000;
609 // test SPECIAL attribute
610 if( nSearchType & ImplFontAttrs::Special )
612 if( nMatchType & ImplFontAttrs::Special )
614 nTestMatch += 10000;
616 else if( !(nSearchType & ImplFontAttrs::AllSerifStyle) )
618 if( nMatchType & ImplFontAttrs::Serif )
620 nTestMatch += 1000*2;
622 else if( nMatchType & ImplFontAttrs::SansSerif )
624 nTestMatch += 1000;
628 else if( (nMatchType & ImplFontAttrs::Special) && !(nSearchType & ImplFontAttrs::Symbol) )
630 nTestMatch -= 1000000;
633 // test DECORATIVE attribute
634 if( nSearchType & ImplFontAttrs::Decorative )
636 if( nMatchType & ImplFontAttrs::Decorative )
638 nTestMatch += 10000;
640 else if( !(nSearchType & ImplFontAttrs::AllSerifStyle) )
642 if( nMatchType & ImplFontAttrs::Serif )
643 nTestMatch += 1000*2;
644 else if ( nMatchType & ImplFontAttrs::SansSerif )
645 nTestMatch += 1000;
648 else if( nMatchType & ImplFontAttrs::Decorative )
650 nTestMatch -= 1000000;
653 // test TITLE+CAPITALS attributes
654 if( nSearchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
656 if( nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
658 nTestMatch += 1000000*2;
660 if( ImplFontAttrs::None == ((nSearchType^nMatchType) & ImplFontAttrs(ImplFontAttrs::Titling | ImplFontAttrs::Capitals)))
662 nTestMatch += 1000000;
664 else if( (nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals)) &&
665 (nMatchType & (ImplFontAttrs::Standard | ImplFontAttrs::Default)) )
667 nTestMatch += 1000000;
670 else if( nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
672 nTestMatch -= 1000000;
675 // test OUTLINE+SHADOW attributes
676 if( nSearchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
678 if( nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
680 nTestMatch += 1000000*2;
682 if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs(ImplFontAttrs::Outline | ImplFontAttrs::Shadow)) )
684 nTestMatch += 1000000;
686 else if( (nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow)) &&
687 (nMatchType & (ImplFontAttrs::Standard | ImplFontAttrs::Default)) )
689 nTestMatch += 1000000;
692 else if ( nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
694 nTestMatch -= 1000000;
697 // test font name substrings
698 // TODO: calculate name matching score using e.g. Levenstein distance
699 if( (rSearchFamilyName.getLength() >= 4) &&
700 (pData->GetMatchFamilyName().getLength() >= 4) &&
701 ((rSearchFamilyName.indexOf( pData->GetMatchFamilyName() ) != -1) ||
702 (pData->GetMatchFamilyName().indexOf( rSearchFamilyName ) != -1)) )
704 nTestMatch += 5000;
706 // test SERIF attribute
707 if( nSearchType & ImplFontAttrs::Serif )
709 if( nMatchType & ImplFontAttrs::Serif )
710 nTestMatch += 1000000*2;
711 else if( nMatchType & ImplFontAttrs::SansSerif )
712 nTestMatch -= 1000000;
715 // test SANSERIF attribute
716 if( nSearchType & ImplFontAttrs::SansSerif )
718 if( nMatchType & ImplFontAttrs::SansSerif )
719 nTestMatch += 1000000;
720 else if ( nMatchType & ImplFontAttrs::Serif )
721 nTestMatch -= 1000000;
724 // test ITALIC attribute
725 if( nSearchType & ImplFontAttrs::Italic )
727 if( pData->GetTypeFaces() & FontTypeFaces::Italic )
728 nTestMatch += 1000000*3;
729 if( nMatchType & ImplFontAttrs::Italic )
730 nTestMatch += 1000000;
732 else if( !(nSearchType & ImplFontAttrs::AllScript) &&
733 ((nMatchType & ImplFontAttrs::Italic) ||
734 !(pData->GetTypeFaces() & FontTypeFaces::NoneItalic)) )
736 nTestMatch -= 1000000*2;
739 // test WIDTH attribute
740 if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) )
742 if( eSearchWidth < WIDTH_NORMAL )
744 if( eSearchWidth == eMatchWidth )
745 nTestMatch += 1000000*3;
746 else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) )
747 nTestMatch += 1000000;
749 else
751 if( eSearchWidth == eMatchWidth )
752 nTestMatch += 1000000*3;
753 else if( eMatchWidth > WIDTH_NORMAL )
754 nTestMatch += 1000000;
757 else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) )
759 nTestMatch -= 1000000;
762 // test WEIGHT attribute
763 if( (eSearchWeight != WEIGHT_DONTKNOW) &&
764 (eSearchWeight != WEIGHT_NORMAL) &&
765 (eSearchWeight != WEIGHT_MEDIUM) )
767 if( eSearchWeight < WEIGHT_NORMAL )
769 if( pData->GetTypeFaces() & FontTypeFaces::Light )
770 nTestMatch += 1000000;
771 if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) )
772 nTestMatch += 1000000;
774 else
776 if( pData->GetTypeFaces() & FontTypeFaces::Bold )
777 nTestMatch += 1000000;
778 if( eMatchWeight > WEIGHT_BOLD )
779 nTestMatch += 1000000;
782 else if( ((eMatchWeight != WEIGHT_DONTKNOW) &&
783 (eMatchWeight != WEIGHT_NORMAL) &&
784 (eMatchWeight != WEIGHT_MEDIUM)) ||
785 !(pData->GetTypeFaces() & FontTypeFaces::Normal) )
787 nTestMatch -= 1000000;
790 // prefer scalable fonts
791 if( pData->GetTypeFaces() & FontTypeFaces::Scalable )
792 nTestMatch += 10000*4;
793 else
794 nTestMatch -= 10000*4;
796 // test STANDARD+DEFAULT+FULL+NORMAL attributes
797 if( nMatchType & ImplFontAttrs::Standard )
798 nTestMatch += 10000*2;
799 if( nMatchType & ImplFontAttrs::Default )
800 nTestMatch += 10000;
801 if( nMatchType & ImplFontAttrs::Full )
802 nTestMatch += 10000;
803 if( nMatchType & ImplFontAttrs::Normal )
804 nTestMatch += 10000;
806 // test OTHERSTYLE attribute
807 if( ((nSearchType ^ nMatchType) & ImplFontAttrs::OtherStyle) != ImplFontAttrs::None )
809 nTestMatch -= 10000;
812 // test ROUNDED attribute
813 if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Rounded) )
814 nTestMatch += 1000;
816 // test TYPEWRITER attribute
817 if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Typewriter) )
818 nTestMatch += 1000;
820 // test GOTHIC attribute
821 if( nSearchType & ImplFontAttrs::Gothic )
823 if( nMatchType & ImplFontAttrs::Gothic )
824 nTestMatch += 1000*3;
825 if( nMatchType & ImplFontAttrs::SansSerif )
826 nTestMatch += 1000*2;
829 // test SCHOOLBOOK attribute
830 if( nSearchType & ImplFontAttrs::Schoolbook )
832 if( nMatchType & ImplFontAttrs::Schoolbook )
833 nTestMatch += 1000*3;
834 if( nMatchType & ImplFontAttrs::Serif )
835 nTestMatch += 1000*2;
838 // compare with best matching font yet
839 if ( nTestMatch > nBestMatch )
841 pFoundData = pData;
842 nBestMatch = nTestMatch;
843 nBestType = nMatchType;
845 else if( nTestMatch == nBestMatch )
847 // some fonts are more suitable defaults
848 if( nMatchType & ImplFontAttrs::Default )
850 pFoundData = pData;
851 nBestType = nMatchType;
853 else if( (nMatchType & ImplFontAttrs::Standard) &&
854 !(nBestType & ImplFontAttrs::Default) )
856 pFoundData = pData;
857 nBestType = nMatchType;
862 return pFoundData;
865 PhysicalFontFamily* PhysicalFontCollection::ImplFindFontFamilyOfDefaultFont() const
867 // try to find one of the default fonts of the
868 // UNICODE, SANSSERIF, SERIF or FIXED default font lists
869 PhysicalFontFamily* pFoundData = nullptr;
870 if (!utl::ConfigManager::IsAvoidConfig())
872 const utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
873 LanguageTag aLanguageTag("en");
874 OUString aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SANS_UNICODE );
875 pFoundData = FindFontFamilyByTokenNames( aFontname );
877 if( pFoundData )
878 return pFoundData;
880 aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SANS );
881 pFoundData = FindFontFamilyByTokenNames( aFontname );
882 if( pFoundData )
883 return pFoundData;
885 aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SERIF );
886 pFoundData = FindFontFamilyByTokenNames( aFontname );
887 if( pFoundData )
888 return pFoundData;
890 aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::FIXED );
891 pFoundData = FindFontFamilyByTokenNames( aFontname );
892 if( pFoundData )
893 return pFoundData;
896 // now try to find a reasonable non-symbol font
898 ImplInitMatchData();
900 PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
901 for(; it != maPhysicalFontFamilies.end(); ++it )
903 PhysicalFontFamily* pData = (*it).second;
904 if( pData->GetMatchType() & ImplFontAttrs::Symbol )
905 continue;
907 pFoundData = pData;
908 if( pData->GetMatchType() & (ImplFontAttrs::Default|ImplFontAttrs::Standard) )
909 break;
911 if( pFoundData )
912 return pFoundData;
914 // finding any font is better than finding no font at all
915 it = maPhysicalFontFamilies.begin();
916 if( it != maPhysicalFontFamilies.end() )
917 pFoundData = (*it).second;
919 return pFoundData;
922 PhysicalFontCollection* PhysicalFontCollection::Clone() const
924 PhysicalFontCollection* pClonedCollection = new PhysicalFontCollection;
925 pClonedCollection->mbMapNames = mbMapNames;
926 pClonedCollection->mpPreMatchHook = mpPreMatchHook;
927 pClonedCollection->mpFallbackHook = mpFallbackHook;
929 // TODO: clone the config-font attributes too?
930 pClonedCollection->mbMatchData = false;
932 PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
933 for(; it != maPhysicalFontFamilies.end(); ++it )
935 const PhysicalFontFamily* pFontFace = (*it).second;
936 pFontFace->UpdateCloneFontList(*pClonedCollection);
939 return pClonedCollection;
942 ImplDeviceFontList* PhysicalFontCollection::GetDeviceFontList() const
944 ImplDeviceFontList* pDeviceFontList = new ImplDeviceFontList;
946 PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
947 for(; it != maPhysicalFontFamilies.end(); ++it )
949 const PhysicalFontFamily* pFontFamily = (*it).second;
950 pFontFamily->UpdateDevFontList( *pDeviceFontList );
953 return pDeviceFontList;
956 ImplDeviceFontSizeList* PhysicalFontCollection::GetDeviceFontSizeList( const OUString& rFontName ) const
958 ImplDeviceFontSizeList* pDeviceFontSizeList = new ImplDeviceFontSizeList;
960 PhysicalFontFamily* pFontFamily = FindFontFamily( rFontName );
961 if( pFontFamily != nullptr )
963 std::set<int> rHeights;
964 pFontFamily->GetFontHeights( rHeights );
966 std::set<int>::const_iterator it = rHeights.begin();
967 for(; it != rHeights.begin(); ++it )
968 pDeviceFontSizeList->Add( *it );
971 return pDeviceFontSizeList;
974 // These are the metric-compatible replacement fonts that are bundled with
975 // LibreOffice, we prefer them over generic substitutions that might be
976 // provided by the system.
977 static const std::map<OUString, OUString> aMetricCompatibleMap =
979 { "Times New Roman", "Liberation Serif" },
980 { "Arial", "Liberation Sans" },
981 { "Arial Narrow", "Liberation Sans Narrow" },
982 { "Courier New", "Liberation Mono" },
983 { "Cambria", "Caladea" },
984 { "Calibri", "Carlito" },
987 static bool FindMetricCompatibleFont(FontSelectPattern& rFontSelData)
989 for (const auto& aSub : aMetricCompatibleMap)
991 if (rFontSelData.maSearchName == GetEnglishSearchFontName(aSub.first))
993 rFontSelData.maSearchName = aSub.second;
994 return true;
998 return false;
1001 PhysicalFontFamily* PhysicalFontCollection::FindFontFamily( FontSelectPattern& rFSD ) const
1003 // give up if no fonts are available
1004 if( !Count() )
1005 return nullptr;
1007 if (getenv("SAL_NO_FONT_LOOKUP") != nullptr)
1009 // Hard code the use of Liberation Sans and skip font search.
1010 sal_Int32 nIndex = 0;
1011 rFSD.maTargetName = GetNextFontToken(rFSD.GetFamilyName(), nIndex);
1012 rFSD.maSearchName = "liberationsans";
1013 PhysicalFontFamily* pFont = ImplFindFontFamilyBySearchName(rFSD.maSearchName);
1014 assert(pFont);
1015 return pFont;
1018 bool bMultiToken = false;
1019 sal_Int32 nTokenPos = 0;
1020 OUString& aSearchName = rFSD.maSearchName; // TODO: get rid of reference
1021 for(;;)
1023 rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
1024 aSearchName = rFSD.maTargetName;
1026 // Until features are properly supported, they are appended to the
1027 // font name, so we need to strip them off so the font is found.
1028 sal_Int32 nFeat = aSearchName.indexOf(FontSelectPatternAttributes::FEAT_PREFIX);
1029 OUString aOrigName = rFSD.maTargetName;
1030 OUString aBaseFontName = aSearchName.copy( 0, (nFeat != -1) ? nFeat : aSearchName.getLength() );
1032 if (nFeat != -1)
1034 aSearchName = aBaseFontName;
1035 rFSD.maTargetName = aBaseFontName;
1038 aSearchName = GetEnglishSearchFontName( aSearchName );
1039 ImplFontSubstitute( aSearchName );
1040 // #114999# special emboldening for Ricoh fonts
1041 // TODO: smarter check for special cases by using PreMatch infrastructure?
1042 if( (rFSD.GetWeight() > WEIGHT_MEDIUM) &&
1043 aSearchName.startsWithIgnoreAsciiCase( "hg" ) )
1045 OUString aBoldName;
1046 if( aSearchName.startsWithIgnoreAsciiCase( "hggothicb" ) )
1047 aBoldName = "hggothice";
1048 else if( aSearchName.startsWithIgnoreAsciiCase( "hgpgothicb" ) )
1049 aBoldName = "hgpgothice";
1050 else if( aSearchName.startsWithIgnoreAsciiCase( "hgminchol" ) )
1051 aBoldName = "hgminchob";
1052 else if( aSearchName.startsWithIgnoreAsciiCase( "hgpminchol" ) )
1053 aBoldName = "hgpminchob";
1054 else if( aSearchName.equalsIgnoreAsciiCase( "hgminchob" ) )
1055 aBoldName = "hgminchoe";
1056 else if( aSearchName.equalsIgnoreAsciiCase( "hgpminchob" ) )
1057 aBoldName = "hgpminchoe";
1059 if( !aBoldName.isEmpty() && ImplFindFontFamilyBySearchName( aBoldName ) )
1061 // the other font is available => use it
1062 aSearchName = aBoldName;
1063 // prevent synthetic emboldening of bold version
1064 rFSD.SetWeight(WEIGHT_DONTKNOW);
1068 // restore the features to make the font selection data unique
1069 rFSD.maTargetName = aOrigName;
1071 // check if the current font name token or its substitute is valid
1072 PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
1073 if( pFoundData )
1074 return pFoundData;
1076 // some systems provide special customization
1077 // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
1078 // because the system wants to map it to another font first, e.g. "Helvetica"
1080 // use the target name to search in the prematch hook
1081 rFSD.maTargetName = aBaseFontName;
1083 // Related: fdo#49271 RTF files often contain weird-ass
1084 // Win 3.1/Win95 style fontnames which attempt to put the
1085 // charset encoding into the filename
1086 // http://www.webcenter.ru/~kazarn/eng/fonts_ttf.htm
1087 OUString sStrippedName = StripScriptFromName(rFSD.maTargetName);
1088 if (sStrippedName != rFSD.maTargetName)
1090 rFSD.maTargetName = sStrippedName;
1091 aSearchName = GetEnglishSearchFontName(rFSD.maTargetName);
1092 pFoundData = ImplFindFontFamilyBySearchName(aSearchName);
1093 if( pFoundData )
1094 return pFoundData;
1097 if (FindMetricCompatibleFont(rFSD) ||
1098 (mpPreMatchHook && mpPreMatchHook->FindFontSubstitute(rFSD)))
1100 aSearchName = GetEnglishSearchFontName(aSearchName);
1103 // the prematch hook uses the target name to search, but we now need
1104 // to restore the features to make the font selection data unique
1105 rFSD.maTargetName = aOrigName;
1107 pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
1108 if( pFoundData )
1109 return pFoundData;
1111 // break after last font name token was checked unsuccessfully
1112 if( nTokenPos == -1)
1113 break;
1114 bMultiToken = true;
1117 // if the first font was not available find the next available font in
1118 // the semicolon separated list of font names. A font is also considered
1119 // available when there is a matching entry in the Tools->Options->Fonts
1120 // dialog with neither ALWAYS nor SCREENONLY flags set and the substitution
1121 // font is available
1122 for( nTokenPos = 0; nTokenPos != -1; )
1124 if( bMultiToken )
1126 rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
1127 aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
1129 else
1130 nTokenPos = -1;
1131 if (FindMetricCompatibleFont(rFSD) ||
1132 (mpPreMatchHook && mpPreMatchHook->FindFontSubstitute(rFSD)))
1134 aSearchName = GetEnglishSearchFontName( aSearchName );
1136 ImplFontSubstitute( aSearchName );
1137 PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
1138 if( pFoundData )
1139 return pFoundData;
1142 // if no font with a directly matching name is available use the
1143 // first font name token and get its attributes to find a replacement
1144 if ( bMultiToken )
1146 nTokenPos = 0;
1147 rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
1148 aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
1151 OUString aSearchShortName;
1152 OUString aSearchFamilyName;
1153 FontWeight eSearchWeight = rFSD.GetWeight();
1154 FontWidth eSearchWidth = rFSD.GetWidthType();
1155 ImplFontAttrs nSearchType = ImplFontAttrs::None;
1156 utl::FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName,
1157 eSearchWeight, eSearchWidth, nSearchType );
1159 // note: the search name was already translated to english (if possible)
1160 // use the font's shortened name if needed
1161 if ( aSearchShortName != aSearchName )
1163 PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchShortName );
1164 if( pFoundData )
1166 #ifdef UNX
1167 /* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is
1168 a korean bitmap font that is not suitable here. Use the font replacement table,
1169 that automatically leads to the desired "HG Mincho Light J". Same story for
1170 MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
1171 if ((aSearchName != "msmincho") && (aSearchName != "msgothic"))
1172 // TODO: add heuristic to only throw out the fake ms* fonts
1173 #endif
1175 return pFoundData;
1180 // use font fallback
1181 const utl::FontNameAttr* pFontAttr = nullptr;
1182 if (!aSearchName.isEmpty() && !utl::ConfigManager::IsAvoidConfig())
1184 // get fallback info using FontSubstConfiguration and
1185 // the target name, it's shortened name and family name in that order
1186 const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
1187 pFontAttr = rFontSubst.getSubstInfo( aSearchName );
1188 if ( !pFontAttr && (aSearchShortName != aSearchName) )
1189 pFontAttr = rFontSubst.getSubstInfo( aSearchShortName );
1190 if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) )
1191 pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName );
1193 // try the font substitutions suggested by the fallback info
1194 if( pFontAttr )
1196 PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySubstFontAttr( *pFontAttr );
1197 if( pFoundData )
1198 return pFoundData;
1202 // if a target symbol font is not available use a default symbol font
1203 if( rFSD.IsSymbolFont() )
1205 LanguageTag aDefaultLanguageTag("en");
1206 if (utl::ConfigManager::IsAvoidConfig())
1207 aSearchName = "OpenSymbol";
1208 else
1209 aSearchName = utl::DefaultFontConfiguration::get().getDefaultFont( aDefaultLanguageTag, DefaultFontType::SYMBOL );
1210 PhysicalFontFamily* pFoundData = FindFontFamilyByTokenNames( aSearchName );
1211 if( pFoundData )
1212 return pFoundData;
1215 // now try the other font name tokens
1216 while( nTokenPos != -1 )
1218 rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
1219 if( rFSD.maTargetName.isEmpty() )
1220 continue;
1222 aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
1224 OUString aTempShortName;
1225 OUString aTempFamilyName;
1226 ImplFontAttrs nTempType = ImplFontAttrs::None;
1227 FontWeight eTempWeight = rFSD.GetWeight();
1228 FontWidth eTempWidth = WIDTH_DONTKNOW;
1229 utl::FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName,
1230 eTempWeight, eTempWidth, nTempType );
1232 // use a shortend token name if available
1233 if( aTempShortName != aSearchName )
1235 PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aTempShortName );
1236 if( pFoundData )
1237 return pFoundData;
1240 const utl::FontNameAttr* pTempFontAttr = nullptr;
1241 if (!utl::ConfigManager::IsAvoidConfig())
1243 // use a font name from font fallback list to determine font attributes
1244 // get fallback info using FontSubstConfiguration and
1245 // the target name, it's shortened name and family name in that order
1246 const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
1247 pTempFontAttr = rFontSubst.getSubstInfo( aSearchName );
1249 if ( !pTempFontAttr && (aTempShortName != aSearchName) )
1250 pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName );
1252 if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) )
1253 pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName );
1256 // try the font substitutions suggested by the fallback info
1257 if( pTempFontAttr )
1259 PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySubstFontAttr( *pTempFontAttr );
1260 if( pFoundData )
1261 return pFoundData;
1262 if( !pFontAttr )
1263 pFontAttr = pTempFontAttr;
1267 // if still needed use the alias names of the installed fonts
1268 if( mbMapNames )
1270 PhysicalFontFamily* pFoundData = ImplFindFontFamilyByAliasName( rFSD.maTargetName, aSearchShortName );
1271 if( pFoundData )
1272 return pFoundData;
1275 // if still needed use the font request's attributes to find a good match
1276 if (MsLangId::isSimplifiedChinese(rFSD.meLanguage))
1277 nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_SC;
1278 else if (MsLangId::isTraditionalChinese(rFSD.meLanguage))
1279 nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_TC;
1280 else if (MsLangId::isKorean(rFSD.meLanguage))
1281 nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_KR;
1282 else if (rFSD.meLanguage == LANGUAGE_JAPANESE)
1283 nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_JP;
1284 else
1286 nSearchType |= lcl_IsCJKFont( rFSD.GetFamilyName() );
1287 if( rFSD.IsSymbolFont() )
1288 nSearchType |= ImplFontAttrs::Symbol;
1291 PhysicalFontFamily::CalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.GetFamilyType(), pFontAttr );
1292 PhysicalFontFamily* pFoundData = FindFontFamilyByAttributes( nSearchType,
1293 eSearchWeight, eSearchWidth, rFSD.GetItalic(), aSearchFamilyName );
1295 if( pFoundData )
1297 // overwrite font selection attributes using info from the typeface flags
1298 if( (eSearchWeight >= WEIGHT_BOLD) &&
1299 (eSearchWeight > rFSD.GetWeight()) &&
1300 (pFoundData->GetTypeFaces() & FontTypeFaces::Bold) )
1302 rFSD.SetWeight( eSearchWeight );
1304 else if( (eSearchWeight < WEIGHT_NORMAL) &&
1305 (eSearchWeight < rFSD.GetWeight()) &&
1306 (eSearchWeight != WEIGHT_DONTKNOW) &&
1307 (pFoundData->GetTypeFaces() & FontTypeFaces::Light) )
1309 rFSD.SetWeight( eSearchWeight );
1312 if( (nSearchType & ImplFontAttrs::Italic) &&
1313 ((rFSD.GetItalic() == ITALIC_DONTKNOW) ||
1314 (rFSD.GetItalic() == ITALIC_NONE)) &&
1315 (pFoundData->GetTypeFaces() & FontTypeFaces::Italic) )
1317 rFSD.SetItalic( ITALIC_NORMAL );
1320 else
1322 // if still needed fall back to default fonts
1323 pFoundData = ImplFindFontFamilyOfDefaultFont();
1326 return pFoundData;
1329 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */