LibreOffice Module vcl (master)  1
PhysicalFontCollection.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 
20 #include <sal/config.h>
21 
22 #include <memory>
23 
25 #include <i18nlangtag/mslangid.hxx>
26 #include <unotools/configmgr.hxx>
27 #include <unotools/fontdefs.hxx>
28 #include <o3tl/sorted_vector.hxx>
29 #include <outdev.h>
32 
33 static ImplFontAttrs lcl_IsCJKFont( const OUString& rFontName )
34 {
35  // Test, if Fontname includes CJK characters --> In this case we
36  // mention that it is a CJK font
37  for(int i = 0; i < rFontName.getLength(); i++)
38  {
39  const sal_Unicode ch = rFontName[i];
40  // japanese
41  if ( ((ch >= 0x3040) && (ch <= 0x30FF)) ||
42  ((ch >= 0x3190) && (ch <= 0x319F)) )
43  return ImplFontAttrs::CJK|ImplFontAttrs::CJK_JP;
44 
45  // korean
46  if ( ((ch >= 0xAC00) && (ch <= 0xD7AF)) ||
47  ((ch >= 0xA960) && (ch <= 0xA97F)) ||
48  ((ch >= 0xD7B0) && (ch <= 0xD7FF)) ||
49  ((ch >= 0x3130) && (ch <= 0x318F)) ||
50  ((ch >= 0x1100) && (ch <= 0x11FF)) )
51  return ImplFontAttrs::CJK|ImplFontAttrs::CJK_KR;
52 
53  // chinese
54  if ( (ch >= 0x3400) && (ch <= 0x9FFF) )
55  return ImplFontAttrs::CJK|ImplFontAttrs::CJK_TC|ImplFontAttrs::CJK_SC;
56 
57  // cjk
58  if ( ((ch >= 0x3000) && (ch <= 0xD7AF)) ||
59  ((ch >= 0xFF00) && (ch <= 0xFFEE)) )
60  return ImplFontAttrs::CJK;
61 
62  }
63 
64  return ImplFontAttrs::None;
65 }
66 
68  : mbMatchData( false )
69  , mpPreMatchHook( nullptr )
70  , mpFallbackHook( nullptr )
71  , mnFallbackCount( -1 )
72 {}
73 
75 {
76  Clear();
77 }
78 
80 {
81  mpPreMatchHook = pHook;
82 }
83 
85 {
86  mpFallbackHook = pHook;
87 }
88 
90 {
91  // remove fallback lists
92  mpFallbackList.reset();
93  mnFallbackCount = -1;
94 
95  // clear all entries in the device font list
96  maPhysicalFontFamilies.clear();
97 
98  // match data must be recalculated too
99  mbMatchData = false;
100 }
101 
103 {
104  // normalized family names of fonts suited for glyph fallback
105  // if a font is available related fonts can be ignored
106  // TODO: implement dynamic lists
107  static const char* aGlyphFallbackList[] = {
108  // empty strings separate the names of unrelated fonts
109  "eudc", "",
110  "arialunicodems", "cyberbit", "code2000", "",
111  "andalesansui", "",
112  "starsymbol", "opensymbol", "",
113  "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "",
114  "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "",
115  "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "",
116  "tahoma", "dejavusans", "timesnewroman", "liberationsans", "",
117  "shree", "mangal", "",
118  "raavi", "shruti", "tunga", "",
119  "latha", "gautami", "kartika", "vrinda", "",
120  "shayyalmt", "naskmt", "scheherazade", "",
121  "david", "nachlieli", "lucidagrande", "",
122  "norasi", "angsanaupc", "",
123  "khmerossystem", "",
124  "muktinarrow", "",
125  "phetsarathot", "",
126  "padauk", "pinlonmyanmar", "",
127  "iskoolapota", "lklug", "",
128  nullptr
129  };
130 
131  bool bHasEudc = false;
132  int nMaxLevel = 0;
133  int nBestQuality = 0;
134  std::unique_ptr<std::array<PhysicalFontFamily*,MAX_GLYPHFALLBACK>> pFallbackList;
135 
136  for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames )
137  {
138  // advance to next sub-list when end-of-sublist marker
139  if( !**ppNames ) // #i46456# check for empty string, i.e., deref string itself not only ptr to it
140  {
141  if( nBestQuality > 0 )
142  if( ++nMaxLevel >= MAX_GLYPHFALLBACK )
143  break;
144 
145  if( !ppNames[1] )
146  break;
147 
148  nBestQuality = 0;
149  continue;
150  }
151 
152  // test if the glyph fallback candidate font is available and scalable
153  OUString aTokenName( *ppNames, strlen(*ppNames), RTL_TEXTENCODING_UTF8 );
154  PhysicalFontFamily* pFallbackFont = FindFontFamily( aTokenName );
155 
156  if( !pFallbackFont )
157  continue;
158 
159  // keep the best font of the glyph fallback sub-list
160  if( nBestQuality < pFallbackFont->GetMinQuality() )
161  {
162  nBestQuality = pFallbackFont->GetMinQuality();
163  // store available glyph fallback fonts
164  if( !pFallbackList )
165  pFallbackList.reset(new std::array<PhysicalFontFamily*,MAX_GLYPHFALLBACK>);
166 
167  (*pFallbackList)[ nMaxLevel ] = pFallbackFont;
168  if( !bHasEudc && !nMaxLevel )
169  bHasEudc = !strncmp( *ppNames, "eudc", 5 );
170  }
171  }
172 
173  mnFallbackCount = nMaxLevel;
174  mpFallbackList = std::move(pFallbackList);
175 }
176 
178  LogicalFontInstance* pFontInstance,
179  OUString& rMissingCodes,
180  int nFallbackLevel ) const
181 {
182  PhysicalFontFamily* pFallbackData = nullptr;
183 
184  // find a matching font candidate for platform specific glyph fallback
185  if( mpFallbackHook )
186  {
187  // check cache for the first matching entry
188  // to avoid calling the expensive fallback hook (#i83491#)
189  sal_UCS4 cChar = 0;
190  bool bCached = true;
191  sal_Int32 nStrIndex = 0;
192  while( nStrIndex < rMissingCodes.getLength() )
193  {
194  cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
195  bCached = pFontInstance->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName );
196 
197  // ignore entries which don't have a fallback
198  if( !bCached || !rFontSelData.maSearchName.isEmpty() )
199  break;
200  }
201 
202  if( bCached )
203  {
204  // there is a matching fallback in the cache
205  // so update rMissingCodes with codepoints not yet resolved by this fallback
206  int nRemainingLength = 0;
207  std::unique_ptr<sal_UCS4[]> const pRemainingCodes(new sal_UCS4[rMissingCodes.getLength()]);
208  OUString aFontName;
209 
210  while( nStrIndex < rMissingCodes.getLength() )
211  {
212  cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
213  bCached = pFontInstance->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName );
214  if( !bCached || (rFontSelData.maSearchName != aFontName) )
215  pRemainingCodes[ nRemainingLength++ ] = cChar;
216  }
217  rMissingCodes = OUString( pRemainingCodes.get(), nRemainingLength );
218  }
219  else
220  {
221  OUString aOldMissingCodes = rMissingCodes;
222 
223  // call the hook to query the best matching glyph fallback font
224  if (mpFallbackHook->FindFontSubstitute(rFontSelData, pFontInstance, rMissingCodes))
225  // apply outdev3.cxx specific fontname normalization
226  rFontSelData.maSearchName = GetEnglishSearchFontName( rFontSelData.maSearchName );
227  else
228  rFontSelData.maSearchName.clear();
229 
230  // See fdo#32665 for an example. FreeSerif that has glyphs in normal
231  // font, but not in the italic or bold version
232  bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix();
233 
234  // Cache the result even if there was no match, unless its from part of a font for which the properties need
235  // to be faked. We need to rework this cache to take into account that fontconfig can return different fonts
236  // for different input sizes, weights, etc. Basically the cache is way to naive
237  if (!bSubSetOfFontRequiresPropertyFaking)
238  {
239  for(;;)
240  {
241  if( !pFontInstance->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
242  pFontInstance->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
243  if( nStrIndex >= aOldMissingCodes.getLength() )
244  break;
245  cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
246  }
247  if( !rFontSelData.maSearchName.isEmpty() )
248  {
249  // remove cache entries that were still not resolved
250  for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
251  {
252  cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
253  pFontInstance->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
254  }
255  }
256  }
257  }
258 
259  // find the matching device font
260  if( !rFontSelData.maSearchName.isEmpty() )
261  pFallbackData = FindFontFamily( rFontSelData.maSearchName );
262  }
263 
264  // else find a matching font candidate for generic glyph fallback
265  if( !pFallbackData )
266  {
267  // initialize font candidates for generic glyph fallback if needed
268  if( mnFallbackCount < 0 )
270 
271  // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook
272  if( nFallbackLevel < mnFallbackCount )
273  pFallbackData = (*mpFallbackList)[ nFallbackLevel ];
274  }
275 
276  return pFallbackData;
277 }
278 
280 {
281  OUString aSearchName = GetEnglishSearchFontName( pNewData->GetFamilyName() );
282 
283  PhysicalFontFamily* pFoundData = FindOrCreateFontFamily( aSearchName );
284 
285  pFoundData->AddFontFace( pNewData );
286 }
287 
288 // find the font from the normalized font family name
290 {
291  // must be called with a normalized name.
292  assert( GetEnglishSearchFontName( rSearchName ) == rSearchName );
293 
294  PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( rSearchName );
295  if( it == maPhysicalFontFamilies.end() )
296  return nullptr;
297 
298  PhysicalFontFamily* pFoundData = (*it).second.get();
299  return pFoundData;
300 }
301 
303 {
305 }
306 
308 {
309  PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( rFamilyName );
310  PhysicalFontFamily* pFoundData = nullptr;
311 
312  if( it != maPhysicalFontFamilies.end() )
313  pFoundData = (*it).second.get();
314 
315  if( !pFoundData )
316  {
317  pFoundData = new PhysicalFontFamily( rFamilyName );
318  maPhysicalFontFamilies[ rFamilyName ].reset(pFoundData);
319  }
320 
321  return pFoundData;
322 }
323 
325 {
326  PhysicalFontFamily* pFoundData = nullptr;
327 
328  // use normalized font name tokens to find the font
329  for( sal_Int32 nTokenPos = 0; nTokenPos != -1; )
330  {
331  OUString aFamilyName = GetNextFontToken( rTokenStr, nTokenPos );
332  if( aFamilyName.isEmpty() )
333  continue;
334 
335  pFoundData = FindFontFamily( aFamilyName );
336 
337  if( pFoundData )
338  break;
339  }
340 
341  return pFoundData;
342 }
343 
345 {
346  PhysicalFontFamily* pFoundData = nullptr;
347 
348  // use the font substitutions suggested by the FontNameAttr to find the font
349  for (auto const& substitution : rFontAttr.Substitutions)
350  {
351  pFoundData = FindFontFamily(substitution);
352  if( pFoundData )
353  return pFoundData;
354  }
355 
356  // use known attributes from the configuration to find a matching substitute
357  const ImplFontAttrs nSearchType = rFontAttr.Type;
358  if( nSearchType != ImplFontAttrs::None )
359  {
360  const FontWeight eSearchWeight = rFontAttr.Weight;
361  const FontWidth eSearchWidth = rFontAttr.Width;
362  const FontItalic eSearchSlant = ITALIC_DONTKNOW;
363 
364  pFoundData = FindFontFamilyByAttributes( nSearchType,
365  eSearchWeight, eSearchWidth, eSearchSlant, "" );
366 
367  if( pFoundData )
368  return pFoundData;
369  }
370 
371  return nullptr;
372 }
373 
375 {
376  // short circuit if already done
377  if( mbMatchData )
378  return;
379  mbMatchData = true;
380 
382  return;
383 
384  // calculate MatchData for all entries
385  const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
386 
387  for (auto const& family : maPhysicalFontFamilies)
388  {
389  const OUString& rSearchName = family.first;
390  PhysicalFontFamily* pEntry = family.second.get();
391 
392  pEntry->InitMatchData( rFontSubst, rSearchName );
393  }
394 }
395 
397  FontWeight eSearchWeight,
398  FontWidth eSearchWidth,
399  FontItalic eSearchItalic,
400  const OUString& rSearchFamilyName ) const
401 {
402  if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) )
403  nSearchType |= ImplFontAttrs::Italic;
404 
405  // don't bother to match attributes if the attributes aren't worth matching
406  if( nSearchType == ImplFontAttrs::None
407  && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL))
408  && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) )
409  return nullptr;
410 
412  PhysicalFontFamily* pFoundData = nullptr;
413 
414  tools::Long nBestMatch = 40000;
415  ImplFontAttrs nBestType = ImplFontAttrs::None;
416 
417  for (auto const& family : maPhysicalFontFamilies)
418  {
419  PhysicalFontFamily* pData = family.second.get();
420 
421  // Get all information about the matching font
422  ImplFontAttrs nMatchType = pData->GetMatchType();
423  FontWeight eMatchWeight= pData->GetMatchWeight();
424  FontWidth eMatchWidth = pData->GetMatchWidth();
425 
426  // Calculate Match Value
427  // 1000000000
428  // 100000000
429  // 10000000 CJK, CTL, None-Latin, Symbol
430  // 1000000 FamilyName, Script, Fixed, -Special, -Decorative,
431  // Titling, Capitals, Outline, Shadow
432  // 100000 Match FamilyName, Serif, SansSerif, Italic,
433  // Width, Weight
434  // 10000 Scalable, Standard, Default,
435  // full, Normal, Knownfont,
436  // Otherstyle, +Special, +Decorative,
437  // 1000 Typewriter, Rounded, Gothic, Schollbook
438  // 100
439  tools::Long nTestMatch = 0;
440 
441  // test CJK script attributes
442  if ( nSearchType & ImplFontAttrs::CJK )
443  {
444  // Matching language
445  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::CJK_AllLang) )
446  nTestMatch += 10000000*3;
447  if( nMatchType & ImplFontAttrs::CJK )
448  nTestMatch += 10000000*2;
449  if( nMatchType & ImplFontAttrs::Full )
450  nTestMatch += 10000000;
451  }
452  else if ( nMatchType & ImplFontAttrs::CJK )
453  {
454  nTestMatch -= 10000000;
455  }
456 
457  // test CTL script attributes
458  if( nSearchType & ImplFontAttrs::CTL )
459  {
460  if( nMatchType & ImplFontAttrs::CTL )
461  nTestMatch += 10000000*2;
462  if( nMatchType & ImplFontAttrs::Full )
463  nTestMatch += 10000000;
464  }
465  else if ( nMatchType & ImplFontAttrs::CTL )
466  {
467  nTestMatch -= 10000000;
468  }
469 
470  // test LATIN script attributes
471  if( nSearchType & ImplFontAttrs::NoneLatin )
472  {
473  if( nMatchType & ImplFontAttrs::NoneLatin )
474  nTestMatch += 10000000*2;
475  if( nMatchType & ImplFontAttrs::Full )
476  nTestMatch += 10000000;
477  }
478 
479  // test SYMBOL attributes
480  if ( nSearchType & ImplFontAttrs::Symbol )
481  {
482  const OUString& rSearchName = family.first;
483  // prefer some special known symbol fonts
484  if ( rSearchName == "starsymbol" )
485  {
486  nTestMatch += 10000000*6+(10000*3);
487  }
488  else if ( rSearchName == "opensymbol" )
489  {
490  nTestMatch += 10000000*6;
491  }
492  else if ( rSearchName == "starbats" ||
493  rSearchName == "wingdings" ||
494  rSearchName == "monotypesorts" ||
495  rSearchName == "dingbats" ||
496  rSearchName == "zapfdingbats" )
497  {
498  nTestMatch += 10000000*5;
499  }
500  else if ( pData->GetTypeFaces() & FontTypeFaces::Symbol )
501  {
502  nTestMatch += 10000000*4;
503  }
504  else
505  {
506  if( nMatchType & ImplFontAttrs::Symbol )
507  nTestMatch += 10000000*2;
508  if( nMatchType & ImplFontAttrs::Full )
509  nTestMatch += 10000000;
510  }
511  }
513  {
514  nTestMatch -= 10000000;
515  }
516  else if ( nMatchType & ImplFontAttrs::Symbol )
517  {
518  nTestMatch -= 10000;
519  }
520 
521  // match stripped family name
522  if( !rSearchFamilyName.isEmpty() && (rSearchFamilyName == pData->GetMatchFamilyName()) )
523  {
524  nTestMatch += 1000000*3;
525  }
526 
527  // match ALLSCRIPT? attribute
528  if( nSearchType & ImplFontAttrs::AllScript )
529  {
530  if( nMatchType & ImplFontAttrs::AllScript )
531  {
532  nTestMatch += 1000000*2;
533  }
534  if( nSearchType & ImplFontAttrs::AllSubscript )
535  {
536  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::AllSubscript) )
537  nTestMatch += 1000000*2;
538  if( ImplFontAttrs::None != ((nSearchType ^ nMatchType) & ImplFontAttrs::BrushScript) )
539  nTestMatch -= 1000000;
540  }
541  }
542  else if( nMatchType & ImplFontAttrs::AllScript )
543  {
544  nTestMatch -= 1000000;
545  }
546 
547  // test MONOSPACE+TYPEWRITER attributes
548  if( nSearchType & ImplFontAttrs::Fixed )
549  {
550  if( nMatchType & ImplFontAttrs::Fixed )
551  nTestMatch += 1000000*2;
552  // a typewriter attribute is even better
553  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Typewriter) )
554  nTestMatch += 10000*2;
555  }
556  else if( nMatchType & ImplFontAttrs::Fixed )
557  {
558  nTestMatch -= 1000000;
559  }
560 
561  // test SPECIAL attribute
562  if( nSearchType & ImplFontAttrs::Special )
563  {
564  if( nMatchType & ImplFontAttrs::Special )
565  {
566  nTestMatch += 10000;
567  }
568  else if( !(nSearchType & ImplFontAttrs::AllSerifStyle) )
569  {
570  if( nMatchType & ImplFontAttrs::Serif )
571  {
572  nTestMatch += 1000*2;
573  }
574  else if( nMatchType & ImplFontAttrs::SansSerif )
575  {
576  nTestMatch += 1000;
577  }
578  }
579  }
580  else if( (nMatchType & ImplFontAttrs::Special) && !(nSearchType & ImplFontAttrs::Symbol) )
581  {
582  nTestMatch -= 1000000;
583  }
584 
585  // test DECORATIVE attribute
586  if( nSearchType & ImplFontAttrs::Decorative )
587  {
588  if( nMatchType & ImplFontAttrs::Decorative )
589  {
590  nTestMatch += 10000;
591  }
592  else if( !(nSearchType & ImplFontAttrs::AllSerifStyle) )
593  {
594  if( nMatchType & ImplFontAttrs::Serif )
595  nTestMatch += 1000*2;
596  else if ( nMatchType & ImplFontAttrs::SansSerif )
597  nTestMatch += 1000;
598  }
599  }
600  else if( nMatchType & ImplFontAttrs::Decorative )
601  {
602  nTestMatch -= 1000000;
603  }
604 
605  // test TITLE+CAPITALS attributes
606  if( nSearchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
607  {
608  if( nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
609  {
610  nTestMatch += 1000000*2;
611  }
612  if( ImplFontAttrs::None == ((nSearchType^nMatchType) & ImplFontAttrs(ImplFontAttrs::Titling | ImplFontAttrs::Capitals)))
613  {
614  nTestMatch += 1000000;
615  }
616  else if( (nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals)) &&
617  (nMatchType & (ImplFontAttrs::Standard | ImplFontAttrs::Default)) )
618  {
619  nTestMatch += 1000000;
620  }
621  }
622  else if( nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
623  {
624  nTestMatch -= 1000000;
625  }
626 
627  // test OUTLINE+SHADOW attributes
628  if( nSearchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
629  {
630  if( nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
631  {
632  nTestMatch += 1000000*2;
633  }
634  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs(ImplFontAttrs::Outline | ImplFontAttrs::Shadow)) )
635  {
636  nTestMatch += 1000000;
637  }
638  else if( (nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow)) &&
639  (nMatchType & (ImplFontAttrs::Standard | ImplFontAttrs::Default)) )
640  {
641  nTestMatch += 1000000;
642  }
643  }
644  else if ( nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
645  {
646  nTestMatch -= 1000000;
647  }
648 
649  // test font name substrings
650  // TODO: calculate name matching score using e.g. Levenstein distance
651  if( (rSearchFamilyName.getLength() >= 4) &&
652  (pData->GetMatchFamilyName().getLength() >= 4) &&
653  ((rSearchFamilyName.indexOf( pData->GetMatchFamilyName() ) != -1) ||
654  (pData->GetMatchFamilyName().indexOf( rSearchFamilyName ) != -1)) )
655  {
656  nTestMatch += 5000;
657  }
658  // test SERIF attribute
659  if( nSearchType & ImplFontAttrs::Serif )
660  {
661  if( nMatchType & ImplFontAttrs::Serif )
662  nTestMatch += 1000000*2;
663  else if( nMatchType & ImplFontAttrs::SansSerif )
664  nTestMatch -= 1000000;
665  }
666 
667  // test SANSERIF attribute
668  if( nSearchType & ImplFontAttrs::SansSerif )
669  {
670  if( nMatchType & ImplFontAttrs::SansSerif )
671  nTestMatch += 1000000;
672  else if ( nMatchType & ImplFontAttrs::Serif )
673  nTestMatch -= 1000000;
674  }
675 
676  // test ITALIC attribute
677  if( nSearchType & ImplFontAttrs::Italic )
678  {
679  if( pData->GetTypeFaces() & FontTypeFaces::Italic )
680  nTestMatch += 1000000*3;
681  if( nMatchType & ImplFontAttrs::Italic )
682  nTestMatch += 1000000;
683  }
684  else if( !(nSearchType & ImplFontAttrs::AllScript) &&
685  ((nMatchType & ImplFontAttrs::Italic) ||
686  !(pData->GetTypeFaces() & FontTypeFaces::NoneItalic)) )
687  {
688  nTestMatch -= 1000000*2;
689  }
690 
691  // test WIDTH attribute
692  if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) )
693  {
694  if( eSearchWidth < WIDTH_NORMAL )
695  {
696  if( eSearchWidth == eMatchWidth )
697  nTestMatch += 1000000*3;
698  else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) )
699  nTestMatch += 1000000;
700  }
701  else
702  {
703  if( eSearchWidth == eMatchWidth )
704  nTestMatch += 1000000*3;
705  else if( eMatchWidth > WIDTH_NORMAL )
706  nTestMatch += 1000000;
707  }
708  }
709  else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) )
710  {
711  nTestMatch -= 1000000;
712  }
713 
714  // test WEIGHT attribute
715  if( (eSearchWeight != WEIGHT_DONTKNOW) &&
716  (eSearchWeight != WEIGHT_NORMAL) &&
717  (eSearchWeight != WEIGHT_MEDIUM) )
718  {
719  if( eSearchWeight < WEIGHT_NORMAL )
720  {
721  if( pData->GetTypeFaces() & FontTypeFaces::Light )
722  nTestMatch += 1000000;
723  if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) )
724  nTestMatch += 1000000;
725  }
726  else
727  {
728  if( pData->GetTypeFaces() & FontTypeFaces::Bold )
729  nTestMatch += 1000000;
730  if( eMatchWeight > WEIGHT_BOLD )
731  nTestMatch += 1000000;
732  }
733  }
734  else if( ((eMatchWeight != WEIGHT_DONTKNOW) &&
735  (eMatchWeight != WEIGHT_NORMAL) &&
736  (eMatchWeight != WEIGHT_MEDIUM)) ||
737  !(pData->GetTypeFaces() & FontTypeFaces::Normal) )
738  {
739  nTestMatch -= 1000000;
740  }
741 
742  // prefer scalable fonts
743  if( pData->GetTypeFaces() & FontTypeFaces::Scalable )
744  nTestMatch += 10000*4;
745  else
746  nTestMatch -= 10000*4;
747 
748  // test STANDARD+DEFAULT+FULL+NORMAL attributes
749  if( nMatchType & ImplFontAttrs::Standard )
750  nTestMatch += 10000*2;
751  if( nMatchType & ImplFontAttrs::Default )
752  nTestMatch += 10000;
753  if( nMatchType & ImplFontAttrs::Full )
754  nTestMatch += 10000;
755  if( nMatchType & ImplFontAttrs::Normal )
756  nTestMatch += 10000;
757 
758  // test OTHERSTYLE attribute
759  if( ((nSearchType ^ nMatchType) & ImplFontAttrs::OtherStyle) != ImplFontAttrs::None )
760  {
761  nTestMatch -= 10000;
762  }
763 
764  // test ROUNDED attribute
765  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Rounded) )
766  nTestMatch += 1000;
767 
768  // test TYPEWRITER attribute
769  if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Typewriter) )
770  nTestMatch += 1000;
771 
772  // test GOTHIC attribute
773  if( nSearchType & ImplFontAttrs::Gothic )
774  {
775  if( nMatchType & ImplFontAttrs::Gothic )
776  nTestMatch += 1000*3;
777  if( nMatchType & ImplFontAttrs::SansSerif )
778  nTestMatch += 1000*2;
779  }
780 
781  // test SCHOOLBOOK attribute
782  if( nSearchType & ImplFontAttrs::Schoolbook )
783  {
784  if( nMatchType & ImplFontAttrs::Schoolbook )
785  nTestMatch += 1000*3;
786  if( nMatchType & ImplFontAttrs::Serif )
787  nTestMatch += 1000*2;
788  }
789 
790  // compare with best matching font yet
791  if ( nTestMatch > nBestMatch )
792  {
793  pFoundData = pData;
794  nBestMatch = nTestMatch;
795  nBestType = nMatchType;
796  }
797  else if( nTestMatch == nBestMatch )
798  {
799  // some fonts are more suitable defaults
800  if( nMatchType & ImplFontAttrs::Default )
801  {
802  pFoundData = pData;
803  nBestType = nMatchType;
804  }
805  else if( (nMatchType & ImplFontAttrs::Standard) &&
806  !(nBestType & ImplFontAttrs::Default) )
807  {
808  pFoundData = pData;
809  nBestType = nMatchType;
810  }
811  }
812  }
813 
814  return pFoundData;
815 }
816 
818 {
819  // try to find one of the default fonts of the
820  // UNICODE, SANSSERIF, SERIF or FIXED default font lists
821  PhysicalFontFamily* pFoundData = nullptr;
823  {
825  LanguageTag aLanguageTag("en");
826  OUString aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SANS_UNICODE );
827  pFoundData = FindFontFamilyByTokenNames( aFontname );
828 
829  if( pFoundData )
830  return pFoundData;
831 
832  aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SANS );
833  pFoundData = FindFontFamilyByTokenNames( aFontname );
834  if( pFoundData )
835  return pFoundData;
836 
837  aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SERIF );
838  pFoundData = FindFontFamilyByTokenNames( aFontname );
839  if( pFoundData )
840  return pFoundData;
841 
842  aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::FIXED );
843  pFoundData = FindFontFamilyByTokenNames( aFontname );
844  if( pFoundData )
845  return pFoundData;
846  }
847 
848  // now try to find a reasonable non-symbol font
849 
851 
852  for (auto const& family : maPhysicalFontFamilies)
853  {
854  PhysicalFontFamily* pData = family.second.get();
855  if( pData->GetMatchType() & ImplFontAttrs::Symbol )
856  continue;
857 
858  pFoundData = pData;
859  if( pData->GetMatchType() & (ImplFontAttrs::Default|ImplFontAttrs::Standard) )
860  break;
861  }
862  if( pFoundData )
863  return pFoundData;
864 
865  // finding any font is better than finding no font at all
866  auto it = maPhysicalFontFamilies.begin();
867  if( it != maPhysicalFontFamilies.end() )
868  pFoundData = (*it).second.get();
869 
870  return pFoundData;
871 }
872 
873 std::shared_ptr<PhysicalFontCollection> PhysicalFontCollection::Clone() const
874 {
875  auto xClonedCollection = std::make_shared<PhysicalFontCollection>();
876  xClonedCollection->mpPreMatchHook = mpPreMatchHook;
877  xClonedCollection->mpFallbackHook = mpFallbackHook;
878 
879  // TODO: clone the config-font attributes too?
880  xClonedCollection->mbMatchData = false;
881 
882  for (auto const& family : maPhysicalFontFamilies)
883  {
884  const PhysicalFontFamily* pFontFace = family.second.get();
885  pFontFace->UpdateCloneFontList(*xClonedCollection);
886  }
887 
888  return xClonedCollection;
889 }
890 
891 std::unique_ptr<vcl::font::PhysicalFontFaceCollection> PhysicalFontCollection::GetFontFaceCollection() const
892 {
893  std::unique_ptr<vcl::font::PhysicalFontFaceCollection> pDeviceFontList(new vcl::font::PhysicalFontFaceCollection);
894 
895  for (auto const& family : maPhysicalFontFamilies)
896  {
897  const PhysicalFontFamily* pFontFamily = family.second.get();
898  pFontFamily->UpdateDevFontList( *pDeviceFontList );
899  }
900 
901  return pDeviceFontList;
902 }
903 
904 std::unique_ptr<ImplDeviceFontSizeList> PhysicalFontCollection::GetDeviceFontSizeList( const OUString& rFontName ) const
905 {
906  std::unique_ptr<ImplDeviceFontSizeList> pDeviceFontSizeList(new ImplDeviceFontSizeList);
907 
908  PhysicalFontFamily* pFontFamily = FindFontFamily( rFontName );
909  if( pFontFamily != nullptr )
910  {
911  o3tl::sorted_vector<int> rHeights;
912  pFontFamily->GetFontHeights( rHeights );
913 
914  for( const auto& rHeight : rHeights )
915  pDeviceFontSizeList->Add( rHeight );
916  }
917 
918  return pDeviceFontSizeList;
919 }
920 
921 // These are the metric-compatible replacement fonts that are bundled with
922 // LibreOffice, we prefer them over generic substitutions that might be
923 // provided by the system.
924 const std::vector<std::pair<OUString, OUString>> aMetricCompatibleMap =
925 {
926  { "Times New Roman", "Liberation Serif" },
927  { "Arial", "Liberation Sans" },
928  { "Arial Narrow", "Liberation Sans Narrow" },
929  { "Courier New", "Liberation Mono" },
930  { "Cambria", "Caladea" },
931  { "Calibri", "Carlito" },
932 };
933 
934 static bool FindMetricCompatibleFont(FontSelectPattern& rFontSelData)
935 {
936  for (const auto& aSub : aMetricCompatibleMap)
937  {
938  if (rFontSelData.maSearchName == GetEnglishSearchFontName(aSub.first))
939  {
940  rFontSelData.maSearchName = aSub.second;
941  return true;
942  }
943  }
944 
945  return false;
946 }
947 
949 {
950  // give up if no fonts are available
951  if( !Count() )
952  return nullptr;
953 
954  static bool noFontLookup = getenv("SAL_NO_FONT_LOOKUP") != nullptr;
955  if (noFontLookup)
956  {
957  // Hard code the use of Liberation Sans and skip font search.
958  sal_Int32 nIndex = 0;
959  rFSD.maTargetName = GetNextFontToken(rFSD.GetFamilyName(), nIndex);
960  rFSD.maSearchName = "liberationsans";
962  assert(pFont);
963  return pFont;
964  }
965 
966  bool bMultiToken = false;
967  sal_Int32 nTokenPos = 0;
968  OUString& aSearchName = rFSD.maSearchName; // TODO: get rid of reference
969  for(;;)
970  {
971  rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
972  aSearchName = rFSD.maTargetName;
973 
974  // Until features are properly supported, they are appended to the
975  // font name, so we need to strip them off so the font is found.
976  sal_Int32 nFeat = aSearchName.indexOf(FontSelectPattern::FEAT_PREFIX);
977  OUString aOrigName = rFSD.maTargetName;
978  OUString aBaseFontName = aSearchName.copy( 0, (nFeat != -1) ? nFeat : aSearchName.getLength() );
979 
980  if (nFeat != -1)
981  {
982  aSearchName = aBaseFontName;
983  rFSD.maTargetName = aBaseFontName;
984  }
985 
986  aSearchName = GetEnglishSearchFontName( aSearchName );
987  ImplFontSubstitute( aSearchName );
988  // #114999# special emboldening for Ricoh fonts
989  // TODO: smarter check for special cases by using PreMatch infrastructure?
990  if( (rFSD.GetWeight() > WEIGHT_MEDIUM) &&
991  aSearchName.startsWithIgnoreAsciiCase( "hg" ) )
992  {
993  OUString aBoldName;
994  if( aSearchName.startsWithIgnoreAsciiCase( "hggothicb" ) )
995  aBoldName = "hggothice";
996  else if( aSearchName.startsWithIgnoreAsciiCase( "hgpgothicb" ) )
997  aBoldName = "hgpgothice";
998  else if( aSearchName.startsWithIgnoreAsciiCase( "hgminchol" ) )
999  aBoldName = "hgminchob";
1000  else if( aSearchName.startsWithIgnoreAsciiCase( "hgpminchol" ) )
1001  aBoldName = "hgpminchob";
1002  else if( aSearchName.equalsIgnoreAsciiCase( "hgminchob" ) )
1003  aBoldName = "hgminchoe";
1004  else if( aSearchName.equalsIgnoreAsciiCase( "hgpminchob" ) )
1005  aBoldName = "hgpminchoe";
1006 
1007  if( !aBoldName.isEmpty() && ImplFindFontFamilyBySearchName( aBoldName ) )
1008  {
1009  // the other font is available => use it
1010  aSearchName = aBoldName;
1011  // prevent synthetic emboldening of bold version
1012  rFSD.SetWeight(WEIGHT_DONTKNOW);
1013  }
1014  }
1015 
1016  // restore the features to make the font selection data unique
1017  rFSD.maTargetName = aOrigName;
1018 
1019  // check if the current font name token or its substitute is valid
1020  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
1021  if( pFoundData )
1022  return pFoundData;
1023 
1024  // some systems provide special customization
1025  // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
1026  // because the system wants to map it to another font first, e.g. "Helvetica"
1027 
1028  // use the target name to search in the prematch hook
1029  rFSD.maTargetName = aBaseFontName;
1030 
1031  // Related: fdo#49271 RTF files often contain weird-ass
1032  // Win 3.1/Win95 style fontnames which attempt to put the
1033  // charset encoding into the filename
1034  // http://www.webcenter.ru/~kazarn/eng/fonts_ttf.htm
1035  OUString sStrippedName = StripScriptFromName(rFSD.maTargetName);
1036  if (sStrippedName != rFSD.maTargetName)
1037  {
1038  rFSD.maTargetName = sStrippedName;
1039  aSearchName = GetEnglishSearchFontName(rFSD.maTargetName);
1040  pFoundData = ImplFindFontFamilyBySearchName(aSearchName);
1041  if( pFoundData )
1042  return pFoundData;
1043  }
1044 
1045  if (FindMetricCompatibleFont(rFSD) ||
1047  {
1048  aSearchName = GetEnglishSearchFontName(aSearchName);
1049  }
1050 
1051  // the prematch hook uses the target name to search, but we now need
1052  // to restore the features to make the font selection data unique
1053  rFSD.maTargetName = aOrigName;
1054 
1055  pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
1056  if( pFoundData )
1057  return pFoundData;
1058 
1059  // break after last font name token was checked unsuccessfully
1060  if( nTokenPos == -1)
1061  break;
1062  bMultiToken = true;
1063  }
1064 
1065  // if the first font was not available find the next available font in
1066  // the semicolon separated list of font names. A font is also considered
1067  // available when there is a matching entry in the Tools->Options->Fonts
1068  // dialog with neither ALWAYS nor SCREENONLY flags set and the substitution
1069  // font is available
1070  for( nTokenPos = 0; nTokenPos != -1; )
1071  {
1072  if( bMultiToken )
1073  {
1074  rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
1075  aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
1076  }
1077  else
1078  nTokenPos = -1;
1079  if (FindMetricCompatibleFont(rFSD) ||
1081  {
1082  aSearchName = GetEnglishSearchFontName( aSearchName );
1083  }
1084  ImplFontSubstitute( aSearchName );
1085  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
1086  if( pFoundData )
1087  return pFoundData;
1088  }
1089 
1090  // if no font with a directly matching name is available use the
1091  // first font name token and get its attributes to find a replacement
1092  if ( bMultiToken )
1093  {
1094  nTokenPos = 0;
1095  rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
1096  aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
1097  }
1098 
1099  OUString aSearchShortName;
1100  OUString aSearchFamilyName;
1101  FontWeight eSearchWeight = rFSD.GetWeight();
1102  FontWidth eSearchWidth = rFSD.GetWidthType();
1103  ImplFontAttrs nSearchType = ImplFontAttrs::None;
1104  utl::FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName,
1105  eSearchWeight, eSearchWidth, nSearchType );
1106 
1107  // note: the search name was already translated to english (if possible)
1108  // use the font's shortened name if needed
1109  if ( aSearchShortName != aSearchName )
1110  {
1111  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchShortName );
1112  if( pFoundData )
1113  {
1114 #ifdef UNX
1115  /* #96738# don't use mincho as a replacement for "MS Mincho" on X11: Mincho is
1116  a korean bitmap font that is not suitable here. Use the font replacement table,
1117  that automatically leads to the desired "HG Mincho Light J". Same story for
1118  MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
1119  if ((aSearchName != "msmincho") && (aSearchName != "msgothic"))
1120  // TODO: add heuristic to only throw out the fake ms* fonts
1121 #endif
1122  {
1123  return pFoundData;
1124  }
1125  }
1126  }
1127 
1128  // use font fallback
1129  const utl::FontNameAttr* pFontAttr = nullptr;
1130  if (!aSearchName.isEmpty() && !utl::ConfigManager::IsFuzzing())
1131  {
1132  // get fallback info using FontSubstConfiguration and
1133  // the target name, it's shortened name and family name in that order
1134  const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
1135  pFontAttr = rFontSubst.getSubstInfo( aSearchName );
1136  if ( !pFontAttr && (aSearchShortName != aSearchName) )
1137  pFontAttr = rFontSubst.getSubstInfo( aSearchShortName );
1138  if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) )
1139  pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName );
1140 
1141  // try the font substitutions suggested by the fallback info
1142  if( pFontAttr )
1143  {
1144  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySubstFontAttr( *pFontAttr );
1145  if( pFoundData )
1146  return pFoundData;
1147  }
1148  }
1149 
1150  // if a target symbol font is not available use a default symbol font
1151  if( rFSD.IsSymbolFont() )
1152  {
1153  LanguageTag aDefaultLanguageTag("en");
1155  aSearchName = "OpenSymbol";
1156  else
1157  aSearchName = utl::DefaultFontConfiguration::get().getDefaultFont( aDefaultLanguageTag, DefaultFontType::SYMBOL );
1158  PhysicalFontFamily* pFoundData = FindFontFamilyByTokenNames( aSearchName );
1159  if( pFoundData )
1160  return pFoundData;
1161  }
1162 
1163  // now try the other font name tokens
1164  while( nTokenPos != -1 )
1165  {
1166  rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
1167  if( rFSD.maTargetName.isEmpty() )
1168  continue;
1169 
1170  aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
1171 
1172  OUString aTempShortName;
1173  OUString aTempFamilyName;
1174  ImplFontAttrs nTempType = ImplFontAttrs::None;
1175  FontWeight eTempWeight = rFSD.GetWeight();
1176  FontWidth eTempWidth = WIDTH_DONTKNOW;
1177  utl::FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName,
1178  eTempWeight, eTempWidth, nTempType );
1179 
1180  // use a shortened token name if available
1181  if( aTempShortName != aSearchName )
1182  {
1183  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aTempShortName );
1184  if( pFoundData )
1185  return pFoundData;
1186  }
1187 
1188  const utl::FontNameAttr* pTempFontAttr = nullptr;
1190  {
1191  // use a font name from font fallback list to determine font attributes
1192  // get fallback info using FontSubstConfiguration and
1193  // the target name, it's shortened name and family name in that order
1194  const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
1195  pTempFontAttr = rFontSubst.getSubstInfo( aSearchName );
1196 
1197  if ( !pTempFontAttr && (aTempShortName != aSearchName) )
1198  pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName );
1199 
1200  if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) )
1201  pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName );
1202  }
1203 
1204  // try the font substitutions suggested by the fallback info
1205  if( pTempFontAttr )
1206  {
1207  PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySubstFontAttr( *pTempFontAttr );
1208  if( pFoundData )
1209  return pFoundData;
1210  if( !pFontAttr )
1211  pFontAttr = pTempFontAttr;
1212  }
1213  }
1214 
1215  // if still needed use the font request's attributes to find a good match
1217  nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_SC;
1219  nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_TC;
1220  else if (MsLangId::isKorean(rFSD.meLanguage))
1221  nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_KR;
1222  else if (rFSD.meLanguage == LANGUAGE_JAPANESE)
1223  nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_JP;
1224  else
1225  {
1226  nSearchType |= lcl_IsCJKFont( rFSD.GetFamilyName() );
1227  if( rFSD.IsSymbolFont() )
1228  nSearchType |= ImplFontAttrs::Symbol;
1229  }
1230 
1231  PhysicalFontFamily::CalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.GetFamilyType(), pFontAttr );
1232  PhysicalFontFamily* pFoundData = FindFontFamilyByAttributes( nSearchType,
1233  eSearchWeight, eSearchWidth, rFSD.GetItalic(), aSearchFamilyName );
1234 
1235  if( pFoundData )
1236  {
1237  // overwrite font selection attributes using info from the typeface flags
1238  if( (eSearchWeight >= WEIGHT_BOLD) &&
1239  (eSearchWeight > rFSD.GetWeight()) &&
1240  (pFoundData->GetTypeFaces() & FontTypeFaces::Bold) )
1241  {
1242  rFSD.SetWeight( eSearchWeight );
1243  }
1244  else if( (eSearchWeight < WEIGHT_NORMAL) &&
1245  (eSearchWeight < rFSD.GetWeight()) &&
1246  (eSearchWeight != WEIGHT_DONTKNOW) &&
1247  (pFoundData->GetTypeFaces() & FontTypeFaces::Light) )
1248  {
1249  rFSD.SetWeight( eSearchWeight );
1250  }
1251 
1252  if( (nSearchType & ImplFontAttrs::Italic) &&
1253  ((rFSD.GetItalic() == ITALIC_DONTKNOW) ||
1254  (rFSD.GetItalic() == ITALIC_NONE)) &&
1255  (pFoundData->GetTypeFaces() & FontTypeFaces::Italic) )
1256  {
1257  rFSD.SetItalic( ITALIC_NORMAL );
1258  }
1259  }
1260  else
1261  {
1262  // if still needed fall back to default fonts
1263  pFoundData = ImplFindFontFamilyOfDefaultFont();
1264  }
1265 
1266  return pFoundData;
1267 }
1268 
1269 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
void Add(PhysicalFontFace *)
sal_Int32 nIndex
PhysicalFontFamily * FindOrCreateFontFamily(const OUString &rFamilyName)
sal_uInt32 sal_UCS4
Definition: vclenum.hxx:192
ImplFontAttrs Type
std::unique_ptr< ImplDeviceFontSizeList > GetDeviceFontSizeList(const OUString &rFontName) const
std::unique_ptr< ContentProperties > pData
FontWeight GetMatchWeight() const
PhysicalFontFamily * ImplFindFontFamilyOfDefaultFont() const
FontWidth
ImplPreMatchFontSubstitution * mpPreMatchHook
PhysicalFontFamily * FindFontFamilyByAttributes(ImplFontAttrs nSearchType, FontWeight, FontWidth, FontItalic, const OUString &rSearchFamily) const
PhysicalFontFamily * GetGlyphFallbackFont(FontSelectPattern &, LogicalFontInstance *pLogicalFont, OUString &rMissingCodes, int nFallbackLevel) const
long Long
bool GetFallbackForUnicode(sal_UCS4, FontWeight eWeight, OUString *pFontName) const
PhysicalFontFamily * FindFontFamilyByTokenNames(const OUString &rTokenStr) const
WIDTH_NORMAL
ImplFontAttrs GetMatchType() const
void InitMatchData(const utl::FontSubstConfiguration &, const OUString &rSearchName)
FontTypeFaces GetTypeFaces() const
void SetFallbackHook(ImplGlyphFallbackFontSubstitution *)
PhysicalFontFamily * ImplFindFontFamilyBySearchName(const OUString &) const
void SetPreMatchHook(ImplPreMatchFontSubstitution *)
WEIGHT_BOLD
sal_uInt16 sal_Unicode
OUString GetEnglishSearchFontName(const OUString &rInName)
ItalicMatrix maItalicMatrix
Definition: fontselect.hxx:69
std::unique_ptr< std::array< PhysicalFontFamily *, MAX_GLYPHFALLBACK > > mpFallbackList
static bool IsFuzzing()
const OUString & GetMatchFamilyName() const
FontItalic GetItalic() const
static bool FindMetricCompatibleFont(FontSelectPattern &rFontSelData)
OUString getDefaultFont(const LanguageTag &rLanguageTag, DefaultFontType nType) const
abstract base class for physical font faces
WEIGHT_DONTKNOW
FontFamily GetFamilyType() const
FontWeight Weight
void SetWeight(const FontWeight eWeight)
int i
static void CalcType(ImplFontAttrs &rType, FontWeight &rWeight, FontWidth &rWidth, FontFamily eFamily, const utl::FontNameAttr *pFontAttr)
FontWeight GetWeight() const
void IgnoreFallbackForUnicode(sal_UCS4, FontWeight eWeight, std::u16string_view rFontName)
ImplFontAttrs
std::unique_ptr< vcl::font::PhysicalFontFaceCollection > GetFontFaceCollection() const
OUString StripScriptFromName(const OUString &_aName)
void SetItalic(const FontItalic eItalic)
WEIGHT_MEDIUM
virtual bool FindFontSubstitute(FontSelectPattern &, LogicalFontInstance *pLogicalFont, OUString &rMissingCodes) const =0
WEIGHT_NORMAL
static ImplFontAttrs lcl_IsCJKFont(const OUString &rFontName)
ITALIC_NONE
static bool isSimplifiedChinese(LanguageType nLang)
ImplGlyphFallbackFontSubstitution * mpFallbackHook
FontWidth GetMatchWidth() const
static DefaultFontConfiguration & get()
PhysicalFontFamily * FindFontFamily(const OUString &rFontName) const
void UpdateDevFontList(vcl::font::PhysicalFontFaceCollection &) const
FontWeight
void UpdateCloneFontList(PhysicalFontCollection &) const
void GetFontHeights(o3tl::sorted_vector< int > &rHeights) const
ITALIC_NORMAL
WIDTH_DONTKNOW
PhysicalFontFamily * ImplFindFontFamilyBySubstFontAttr(const utl::FontNameAttr &) const
virtual bool FindFontSubstitute(FontSelectPattern &) const =0
static const char FEAT_PREFIX
Definition: fontselect.hxx:54
void ImplFontSubstitute(OUString &rFontName)
ITALIC_DONTKNOW
const std::vector< std::pair< OUString, OUString > > aMetricCompatibleMap
static bool isKorean(LanguageType nLang)
LanguageType meLanguage
Definition: fontselect.hxx:64
OUString GetNextFontToken(const OUString &rTokenStr, sal_Int32 &rIndex)
FontWidth GetWidthType() const
bool IsSymbolFont() const
PhysicalFontFamilies maPhysicalFontFamilies
#define MAX_GLYPHFALLBACK
OUString maSearchName
Definition: fontselect.hxx:59
const OUString & GetFamilyName() const
#define LANGUAGE_JAPANESE
OUString maTargetName
Definition: fontselect.hxx:58
void AddFallbackForUnicode(sal_UCS4, FontWeight eWeight, const OUString &rFontName)
FontItalic
::std::vector< OUString > Substitutions
std::shared_ptr< PhysicalFontCollection > Clone() const
static bool isTraditionalChinese(LanguageType nLang)